[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(IN HANDLE hFile,
1425 OUT LPFILETIME lpCreationTime OPTIONAL,
1426 OUT LPFILETIME lpLastAccessTime OPTIONAL,
1427 OUT LPFILETIME lpLastWriteTime OPTIONAL)
1428 {
1429 NTSTATUS Status;
1430 IO_STATUS_BLOCK IoStatusBlock;
1431 FILE_BASIC_INFORMATION FileBasic;
1432
1433 if(IsConsoleHandle(hFile))
1434 {
1435 BaseSetLastNTError(STATUS_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 BaseSetLastNTError(Status);
1447 return FALSE;
1448 }
1449
1450 if (lpCreationTime)
1451 {
1452 lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart;
1453 lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart;
1454 }
1455
1456 if (lpLastAccessTime)
1457 {
1458 lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart;
1459 lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart;
1460 }
1461
1462 if (lpLastWriteTime)
1463 {
1464 lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart;
1465 lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart;
1466 }
1467
1468 return TRUE;
1469 }
1470
1471
1472 /*
1473 * @implemented
1474 */
1475 BOOL WINAPI
1476 SetFileTime(IN HANDLE hFile,
1477 CONST FILETIME *lpCreationTime OPTIONAL,
1478 CONST FILETIME *lpLastAccessTime OPTIONAL,
1479 CONST FILETIME *lpLastWriteTime OPTIONAL)
1480 {
1481 NTSTATUS Status;
1482 IO_STATUS_BLOCK IoStatusBlock;
1483 FILE_BASIC_INFORMATION FileBasic;
1484
1485 if(IsConsoleHandle(hFile))
1486 {
1487 BaseSetLastNTError(STATUS_INVALID_HANDLE);
1488 return FALSE;
1489 }
1490
1491 memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION));
1492
1493 if (lpCreationTime)
1494 {
1495 FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime;
1496 FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime;
1497 }
1498
1499 if (lpLastAccessTime)
1500 {
1501 FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime;
1502 FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime;
1503 }
1504
1505 if (lpLastWriteTime)
1506 {
1507 FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime;
1508 FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime;
1509 }
1510
1511 Status = NtSetInformationFile(hFile,
1512 &IoStatusBlock,
1513 &FileBasic,
1514 sizeof(FILE_BASIC_INFORMATION),
1515 FileBasicInformation);
1516 if (!NT_SUCCESS(Status))
1517 {
1518 BaseSetLastNTError(Status);
1519 return FALSE;
1520 }
1521
1522 return TRUE;
1523 }
1524
1525
1526 /*
1527 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1528 *
1529 * @implemented
1530 */
1531 BOOL WINAPI
1532 SetEndOfFile(HANDLE hFile)
1533 {
1534 IO_STATUS_BLOCK IoStatusBlock;
1535 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1536 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1537 FILE_POSITION_INFORMATION FilePosInfo;
1538 NTSTATUS Status;
1539
1540 if(IsConsoleHandle(hFile))
1541 {
1542 SetLastError(ERROR_INVALID_HANDLE);
1543 return FALSE;
1544 }
1545
1546 //get current position
1547 Status = NtQueryInformationFile(
1548 hFile,
1549 &IoStatusBlock,
1550 &FilePosInfo,
1551 sizeof(FILE_POSITION_INFORMATION),
1552 FilePositionInformation
1553 );
1554
1555 if (!NT_SUCCESS(Status)){
1556 SetLastErrorByStatus(Status);
1557 return FALSE;
1558 }
1559
1560 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1561
1562 /*
1563 NOTE:
1564 This call is not supposed to free up any space after the eof marker
1565 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1566 But...most file systems dispatch both FileEndOfFileInformation
1567 and FileAllocationInformation as they were the same command.
1568
1569 */
1570 Status = NtSetInformationFile(
1571 hFile,
1572 &IoStatusBlock, //out
1573 &EndOfFileInfo,
1574 sizeof(FILE_END_OF_FILE_INFORMATION),
1575 FileEndOfFileInformation
1576 );
1577
1578 if (!NT_SUCCESS(Status)){
1579 SetLastErrorByStatus(Status);
1580 return FALSE;
1581 }
1582
1583 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1584
1585
1586 Status = NtSetInformationFile(
1587 hFile,
1588 &IoStatusBlock, //out
1589 &FileAllocationInfo,
1590 sizeof(FILE_ALLOCATION_INFORMATION),
1591 FileAllocationInformation
1592 );
1593
1594 if (!NT_SUCCESS(Status)){
1595 SetLastErrorByStatus(Status);
1596 return FALSE;
1597 }
1598
1599 return TRUE;
1600
1601 }
1602
1603
1604 /*
1605 * @implemented
1606 */
1607 BOOL
1608 WINAPI
1609 SetFileValidData(
1610 HANDLE hFile,
1611 LONGLONG ValidDataLength
1612 )
1613 {
1614 IO_STATUS_BLOCK IoStatusBlock;
1615 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1616 NTSTATUS Status;
1617
1618 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1619
1620 Status = NtSetInformationFile(
1621 hFile,
1622 &IoStatusBlock, //out
1623 &ValidDataLengthInformation,
1624 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1625 FileValidDataLengthInformation
1626 );
1627
1628 if (!NT_SUCCESS(Status)){
1629 SetLastErrorByStatus(Status);
1630 return FALSE;
1631 }
1632
1633 return TRUE;
1634 }
1635
1636
1637
1638 /*
1639 * @implemented
1640 */
1641 BOOL
1642 WINAPI
1643 SetFileShortNameW(
1644 HANDLE hFile,
1645 LPCWSTR lpShortName)
1646 {
1647 NTSTATUS Status;
1648 ULONG NeededSize;
1649 UNICODE_STRING ShortName;
1650 IO_STATUS_BLOCK IoStatusBlock;
1651 PFILE_NAME_INFORMATION FileNameInfo;
1652
1653 if(IsConsoleHandle(hFile))
1654 {
1655 SetLastError(ERROR_INVALID_HANDLE);
1656 return FALSE;
1657 }
1658
1659 if(!lpShortName)
1660 {
1661 SetLastError(ERROR_INVALID_PARAMETER);
1662 return FALSE;
1663 }
1664
1665 RtlInitUnicodeString(&ShortName, lpShortName);
1666
1667 NeededSize = sizeof(FILE_NAME_INFORMATION) + ShortName.Length + sizeof(WCHAR);
1668 if(!(FileNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
1669 {
1670 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1671 return FALSE;
1672 }
1673
1674 FileNameInfo->FileNameLength = ShortName.Length;
1675 RtlCopyMemory(FileNameInfo->FileName, ShortName.Buffer, ShortName.Length);
1676
1677 Status = NtSetInformationFile(hFile,
1678 &IoStatusBlock, //out
1679 FileNameInfo,
1680 NeededSize,
1681 FileShortNameInformation);
1682
1683 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameInfo);
1684 if(!NT_SUCCESS(Status))
1685 {
1686 SetLastErrorByStatus(Status);
1687 return FALSE;
1688 }
1689
1690 return TRUE;
1691 }
1692
1693
1694 /*
1695 * @implemented
1696 */
1697 BOOL
1698 WINAPI
1699 SetFileShortNameA(
1700 HANDLE hFile,
1701 LPCSTR lpShortName
1702 )
1703 {
1704 PWCHAR ShortNameW;
1705
1706 if(IsConsoleHandle(hFile))
1707 {
1708 SetLastError(ERROR_INVALID_HANDLE);
1709 return FALSE;
1710 }
1711
1712 if(!lpShortName)
1713 {
1714 SetLastError(ERROR_INVALID_PARAMETER);
1715 return FALSE;
1716 }
1717
1718 if (!(ShortNameW = FilenameA2W(lpShortName, FALSE)))
1719 return FALSE;
1720
1721 return SetFileShortNameW(hFile, ShortNameW);
1722 }
1723
1724
1725 /*
1726 * @implemented
1727 */
1728 BOOL
1729 WINAPI
1730 CheckNameLegalDOS8Dot3W(
1731 LPCWSTR lpName,
1732 LPSTR lpOemName OPTIONAL,
1733 DWORD OemNameSize OPTIONAL,
1734 PBOOL pbNameContainsSpaces OPTIONAL,
1735 PBOOL pbNameLegal
1736 )
1737 {
1738 UNICODE_STRING Name;
1739 ANSI_STRING AnsiName;
1740
1741 if(lpName == NULL ||
1742 (lpOemName == NULL && OemNameSize != 0) ||
1743 pbNameLegal == NULL)
1744 {
1745 SetLastError(ERROR_INVALID_PARAMETER);
1746 return FALSE;
1747 }
1748
1749 if(lpOemName != NULL)
1750 {
1751 AnsiName.Buffer = lpOemName;
1752 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
1753 AnsiName.Length = 0;
1754 }
1755
1756 RtlInitUnicodeString(&Name, lpName);
1757
1758 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1759 (lpOemName ? &AnsiName : NULL),
1760 (BOOLEAN*)pbNameContainsSpaces);
1761
1762 return TRUE;
1763 }
1764
1765
1766 /*
1767 * @implemented
1768 */
1769 BOOL
1770 WINAPI
1771 CheckNameLegalDOS8Dot3A(
1772 LPCSTR lpName,
1773 LPSTR lpOemName OPTIONAL,
1774 DWORD OemNameSize OPTIONAL,
1775 PBOOL pbNameContainsSpaces OPTIONAL,
1776 PBOOL pbNameLegal
1777 )
1778 {
1779 UNICODE_STRING Name;
1780 ANSI_STRING AnsiName, AnsiInputName;
1781 NTSTATUS Status;
1782
1783 if(lpName == NULL ||
1784 (lpOemName == NULL && OemNameSize != 0) ||
1785 pbNameLegal == NULL)
1786 {
1787 SetLastError(ERROR_INVALID_PARAMETER);
1788 return FALSE;
1789 }
1790
1791 if(lpOemName != NULL)
1792 {
1793 AnsiName.Buffer = lpOemName;
1794 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
1795 AnsiName.Length = 0;
1796 }
1797
1798 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
1799 if(bIsFileApiAnsi)
1800 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1801 else
1802 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1803
1804 if(!NT_SUCCESS(Status))
1805 {
1806 SetLastErrorByStatus(Status);
1807 return FALSE;
1808 }
1809
1810 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1811 (lpOemName ? &AnsiName : NULL),
1812 (BOOLEAN*)pbNameContainsSpaces);
1813
1814 RtlFreeUnicodeString(&Name);
1815
1816 return TRUE;
1817 }
1818
1819
1820 /*
1821 * @implemented
1822 */
1823 DWORD
1824 WINAPI
1825 GetFinalPathNameByHandleA(IN HANDLE hFile,
1826 OUT LPSTR lpszFilePath,
1827 IN DWORD cchFilePath,
1828 IN DWORD dwFlags)
1829 {
1830 WCHAR FilePathW[MAX_PATH];
1831 UNICODE_STRING FilePathU;
1832 DWORD PrevLastError;
1833 DWORD Ret = 0;
1834
1835 if (cchFilePath != 0 &&
1836 cchFilePath > sizeof(FilePathW) / sizeof(FilePathW[0]))
1837 {
1838 FilePathU.Length = 0;
1839 FilePathU.MaximumLength = (USHORT)cchFilePath * sizeof(WCHAR);
1840 FilePathU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1841 0,
1842 FilePathU.MaximumLength);
1843 if (FilePathU.Buffer == NULL)
1844 {
1845 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1846 return 0;
1847 }
1848 }
1849 else
1850 {
1851 FilePathU.Length = 0;
1852 FilePathU.MaximumLength = sizeof(FilePathW);
1853 FilePathU.Buffer = FilePathW;
1854 }
1855
1856 /* save the last error code */
1857 PrevLastError = GetLastError();
1858 SetLastError(ERROR_SUCCESS);
1859
1860 /* call the unicode version that does all the work */
1861 Ret = GetFinalPathNameByHandleW(hFile,
1862 FilePathU.Buffer,
1863 cchFilePath,
1864 dwFlags);
1865
1866 if (GetLastError() == ERROR_SUCCESS)
1867 {
1868 /* no error, restore the last error code and convert the string */
1869 SetLastError(PrevLastError);
1870
1871 Ret = FilenameU2A_FitOrFail(lpszFilePath,
1872 cchFilePath,
1873 &FilePathU);
1874 }
1875
1876 /* free allocated memory if necessary */
1877 if (FilePathU.Buffer != FilePathW)
1878 {
1879 RtlFreeHeap(RtlGetProcessHeap(),
1880 0,
1881 FilePathU.Buffer);
1882 }
1883
1884 return Ret;
1885 }
1886
1887
1888 /*
1889 * @unimplemented
1890 */
1891 DWORD
1892 WINAPI
1893 GetFinalPathNameByHandleW(IN HANDLE hFile,
1894 OUT LPWSTR lpszFilePath,
1895 IN DWORD cchFilePath,
1896 IN DWORD dwFlags)
1897 {
1898 if (dwFlags & ~(VOLUME_NAME_DOS | VOLUME_NAME_GUID | VOLUME_NAME_NT |
1899 VOLUME_NAME_NONE | FILE_NAME_NORMALIZED | FILE_NAME_OPENED))
1900 {
1901 SetLastError(ERROR_INVALID_PARAMETER);
1902 return 0;
1903 }
1904
1905 UNIMPLEMENTED;
1906 return 0;
1907 }
1908
1909
1910 /*
1911 * @unimplemented
1912 */
1913 BOOL
1914 WINAPI
1915 SetFileBandwidthReservation(IN HANDLE hFile,
1916 IN DWORD nPeriodMilliseconds,
1917 IN DWORD nBytesPerPeriod,
1918 IN BOOL bDiscardable,
1919 OUT LPDWORD lpTransferSize,
1920 OUT LPDWORD lpNumOutstandingRequests)
1921 {
1922 UNIMPLEMENTED;
1923 return FALSE;
1924 }
1925
1926
1927 /*
1928 * @unimplemented
1929 */
1930 BOOL
1931 WINAPI
1932 GetFileBandwidthReservation(IN HANDLE hFile,
1933 OUT LPDWORD lpPeriodMilliseconds,
1934 OUT LPDWORD lpBytesPerPeriod,
1935 OUT LPBOOL pDiscardable,
1936 OUT LPDWORD lpTransferSize,
1937 OUT LPDWORD lpNumOutstandingRequests)
1938 {
1939 UNIMPLEMENTED;
1940 return FALSE;
1941 }
1942
1943
1944 /*
1945 * @unimplemented
1946 */
1947 BOOL
1948 WINAPI
1949 SetFileCompletionNotificationModes(IN HANDLE FileHandle,
1950 IN UCHAR Flags)
1951 {
1952 if (Flags & ~(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE))
1953 {
1954 SetLastError(ERROR_INVALID_PARAMETER);
1955 return FALSE;
1956 }
1957
1958 UNIMPLEMENTED;
1959 return FALSE;
1960 }
1961
1962
1963 /*
1964 * @unimplemented
1965 */
1966 HANDLE
1967 WINAPI
1968 OpenFileById(IN HANDLE hFile,
1969 IN LPFILE_ID_DESCRIPTOR lpFileID,
1970 IN DWORD dwDesiredAccess,
1971 IN DWORD dwShareMode,
1972 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
1973 IN DWORD dwFlags)
1974 {
1975 UNIMPLEMENTED;
1976 return INVALID_HANDLE_VALUE;
1977 }
1978
1979 /*
1980 * @implemented
1981 */
1982 BOOL
1983 WINAPI
1984 ReplaceFileA(
1985 LPCSTR lpReplacedFileName,
1986 LPCSTR lpReplacementFileName,
1987 LPCSTR lpBackupFileName,
1988 DWORD dwReplaceFlags,
1989 LPVOID lpExclude,
1990 LPVOID lpReserved
1991 )
1992 {
1993 WCHAR *replacedW, *replacementW, *backupW = NULL;
1994 BOOL ret;
1995
1996 /* This function only makes sense when the first two parameters are defined */
1997 if (!lpReplacedFileName || !(replacedW = FilenameA2W(lpReplacedFileName, TRUE)))
1998 {
1999 SetLastError(ERROR_INVALID_PARAMETER);
2000 return FALSE;
2001 }
2002
2003 if (!lpReplacementFileName || !(replacementW = FilenameA2W(lpReplacementFileName, TRUE)))
2004 {
2005 HeapFree(GetProcessHeap(), 0, replacedW);
2006 SetLastError(ERROR_INVALID_PARAMETER);
2007 return FALSE;
2008 }
2009
2010 /* The backup parameter, however, is optional */
2011 if (lpBackupFileName)
2012 {
2013 if (!(backupW = FilenameA2W(lpBackupFileName, TRUE)))
2014 {
2015 HeapFree(GetProcessHeap(), 0, replacedW);
2016 HeapFree(GetProcessHeap(), 0, replacementW);
2017 SetLastError(ERROR_INVALID_PARAMETER);
2018 return FALSE;
2019 }
2020 }
2021
2022 ret = ReplaceFileW(replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved);
2023 HeapFree(GetProcessHeap(), 0, replacedW);
2024 HeapFree(GetProcessHeap(), 0, replacementW);
2025 HeapFree(GetProcessHeap(), 0, backupW);
2026
2027 return ret;
2028 }
2029
2030 /*
2031 * @unimplemented
2032 */
2033 BOOL
2034 WINAPI
2035 ReplaceFileW(
2036 LPCWSTR lpReplacedFileName,
2037 LPCWSTR lpReplacementFileName,
2038 LPCWSTR lpBackupFileName,
2039 DWORD dwReplaceFlags,
2040 LPVOID lpExclude,
2041 LPVOID lpReserved
2042 )
2043 {
2044 HANDLE hReplaced = NULL, hReplacement = NULL;
2045 UNICODE_STRING NtReplacedName = { 0, 0, NULL };
2046 UNICODE_STRING NtReplacementName = { 0, 0, NULL };
2047 DWORD Error = ERROR_SUCCESS;
2048 NTSTATUS Status;
2049 BOOL Ret = FALSE;
2050 IO_STATUS_BLOCK IoStatusBlock;
2051 OBJECT_ATTRIBUTES ObjectAttributes;
2052 PVOID Buffer = NULL ;
2053
2054 if (dwReplaceFlags)
2055 FIXME("Ignoring flags %x\n", dwReplaceFlags);
2056
2057 /* First two arguments are mandatory */
2058 if (!lpReplacedFileName || !lpReplacementFileName)
2059 {
2060 SetLastError(ERROR_INVALID_PARAMETER);
2061 return FALSE;
2062 }
2063
2064 /* Back it up */
2065 if(lpBackupFileName)
2066 {
2067 if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
2068 {
2069 Error = GetLastError();
2070 goto Cleanup ;
2071 }
2072 }
2073
2074 /* Open the "replaced" file for reading and writing */
2075 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
2076 {
2077 Error = ERROR_PATH_NOT_FOUND;
2078 goto Cleanup;
2079 }
2080
2081 InitializeObjectAttributes(&ObjectAttributes,
2082 &NtReplacedName,
2083 OBJ_CASE_INSENSITIVE,
2084 NULL,
2085 NULL);
2086
2087 Status = NtOpenFile(&hReplaced,
2088 GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE | WRITE_DAC,
2089 &ObjectAttributes,
2090 &IoStatusBlock,
2091 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2092 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
2093
2094 if (!NT_SUCCESS(Status))
2095 {
2096 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
2097 Error = ERROR_FILE_NOT_FOUND;
2098 else
2099 Error = ERROR_UNABLE_TO_REMOVE_REPLACED;
2100 goto Cleanup;
2101 }
2102
2103 /* Blank it */
2104 SetEndOfFile(hReplaced) ;
2105
2106 /*
2107 * Open the replacement file for reading, writing, and deleting
2108 * (deleting is needed when finished)
2109 */
2110 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
2111 {
2112 Error = ERROR_PATH_NOT_FOUND;
2113 goto Cleanup;
2114 }
2115
2116 InitializeObjectAttributes(&ObjectAttributes,
2117 &NtReplacementName,
2118 OBJ_CASE_INSENSITIVE,
2119 NULL,
2120 NULL);
2121
2122 Status = NtOpenFile(&hReplacement,
2123 GENERIC_READ | DELETE | SYNCHRONIZE,
2124 &ObjectAttributes,
2125 &IoStatusBlock,
2126 0,
2127 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
2128
2129 if (!NT_SUCCESS(Status))
2130 {
2131 Error = RtlNtStatusToDosError(Status);
2132 goto Cleanup;
2133 }
2134
2135 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
2136 if (!Buffer)
2137 {
2138 Error = ERROR_NOT_ENOUGH_MEMORY;
2139 goto Cleanup ;
2140 }
2141 while (Status != STATUS_END_OF_FILE)
2142 {
2143 Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
2144 if (NT_SUCCESS(Status))
2145 {
2146 Status = NtWriteFile(hReplaced, NULL, NULL, NULL, &IoStatusBlock, Buffer,
2147 IoStatusBlock.Information, NULL, NULL) ;
2148 if (!NT_SUCCESS(Status))
2149 {
2150 Error = RtlNtStatusToDosError(Status);
2151 goto Cleanup;
2152 }
2153 }
2154 else if (Status != STATUS_END_OF_FILE)
2155 {
2156 Error = RtlNtStatusToDosError(Status);
2157 goto Cleanup;
2158 }
2159 }
2160
2161 Ret = TRUE;
2162
2163 /* Perform resource cleanup */
2164 Cleanup:
2165 if (hReplaced) NtClose(hReplaced);
2166 if (hReplacement) NtClose(hReplacement);
2167 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
2168
2169 if (NtReplacementName.Buffer)
2170 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
2171 if (NtReplacedName.Buffer)
2172 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
2173
2174 /* If there was an error, set the error code */
2175 if(!Ret)
2176 {
2177 TRACE("ReplaceFileW failed (error=%d)\n", Error);
2178 SetLastError(Error);
2179 }
2180 return Ret;
2181 }
2182
2183 /* EOF */