- Robert Horvath: Always limit destLen to MAX_PATH (modified to an if condition by...
[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 * GetTempFileName is modified from WINE [ Alexandre Juiliard ]
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(HANDLE hFile)
410 {
411 NTSTATUS errCode;
412 IO_STATUS_BLOCK IoStatusBlock;
413
414 hFile = TranslateStdHandle(hFile);
415
416 if (IsConsoleHandle(hFile))
417 {
418 return FALSE;
419 }
420
421 errCode = NtFlushBuffersFile(hFile,
422 &IoStatusBlock);
423 if (!NT_SUCCESS(errCode))
424 {
425 SetLastErrorByStatus(errCode);
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 GetTempFileNameA( LPCSTR path, LPCSTR prefix, UINT unique, LPSTR buffer)
1216 {
1217 WCHAR BufferW[MAX_PATH];
1218 PWCHAR PathW;
1219 WCHAR PrefixW[3+1];
1220 UINT ret;
1221
1222 if (!(PathW = FilenameA2W(path, FALSE)))
1223 return 0;
1224
1225 if (prefix)
1226 FilenameA2W_N(PrefixW, 3+1, prefix, -1);
1227
1228 ret = GetTempFileNameW(PathW, prefix ? PrefixW : NULL, unique, BufferW);
1229
1230 if (ret)
1231 FilenameW2A_N(buffer, MAX_PATH, BufferW, -1);
1232
1233 return ret;
1234 }
1235
1236 /***********************************************************************
1237 * GetTempFileNameW (KERNEL32.@)
1238 */
1239 UINT WINAPI GetTempFileNameW( LPCWSTR path, LPCWSTR prefix, UINT unique, LPWSTR buffer )
1240 {
1241 static const WCHAR formatW[] = L"%x.tmp";
1242
1243 int i;
1244 LPWSTR p;
1245
1246 if ( !path || !buffer )
1247 {
1248 SetLastError( ERROR_INVALID_PARAMETER );
1249 return 0;
1250 }
1251
1252 wcscpy( buffer, path );
1253 p = buffer + wcslen(buffer);
1254
1255 /* add a \, if there isn't one */
1256 if ((p == buffer) || (p[-1] != '\\')) *p++ = '\\';
1257
1258 if ( prefix )
1259 for (i = 3; (i > 0) && (*prefix); i--) *p++ = *prefix++;
1260
1261 unique &= 0xffff;
1262
1263 if (unique) swprintf( p, formatW, unique );
1264 else
1265 {
1266 /* get a "random" unique number and try to create the file */
1267 HANDLE handle;
1268 UINT num = GetTickCount() & 0xffff;
1269
1270 if (!num) num = 1;
1271 unique = num;
1272 do
1273 {
1274 swprintf( p, formatW, unique );
1275 handle = CreateFileW( buffer, GENERIC_WRITE, 0, NULL,
1276 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0 );
1277 if (handle != INVALID_HANDLE_VALUE)
1278 { /* We created it */
1279 TRACE("created %S\n", buffer);
1280 CloseHandle( handle );
1281 break;
1282 }
1283 if (GetLastError() != ERROR_FILE_EXISTS &&
1284 GetLastError() != ERROR_SHARING_VIOLATION)
1285 break; /* No need to go on */
1286 if (!(++unique & 0xffff)) unique = 1;
1287 } while (unique != num);
1288 }
1289
1290 TRACE("returning %S\n", buffer);
1291 return unique;
1292 }
1293
1294
1295
1296
1297
1298 /*
1299 * @implemented
1300 */
1301 BOOL WINAPI
1302 GetFileTime(HANDLE hFile,
1303 LPFILETIME lpCreationTime,
1304 LPFILETIME lpLastAccessTime,
1305 LPFILETIME lpLastWriteTime)
1306 {
1307 IO_STATUS_BLOCK IoStatusBlock;
1308 FILE_BASIC_INFORMATION FileBasic;
1309 NTSTATUS Status;
1310
1311 if(IsConsoleHandle(hFile))
1312 {
1313 SetLastError(ERROR_INVALID_HANDLE);
1314 return FALSE;
1315 }
1316
1317 Status = NtQueryInformationFile(hFile,
1318 &IoStatusBlock,
1319 &FileBasic,
1320 sizeof(FILE_BASIC_INFORMATION),
1321 FileBasicInformation);
1322 if (!NT_SUCCESS(Status))
1323 {
1324 SetLastErrorByStatus(Status);
1325 return FALSE;
1326 }
1327
1328 if (lpCreationTime)
1329 memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
1330 if (lpLastAccessTime)
1331 memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
1332 if (lpLastWriteTime)
1333 memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
1334
1335 return TRUE;
1336 }
1337
1338
1339 /*
1340 * @implemented
1341 */
1342 BOOL WINAPI
1343 SetFileTime(HANDLE hFile,
1344 CONST FILETIME *lpCreationTime,
1345 CONST FILETIME *lpLastAccessTime,
1346 CONST FILETIME *lpLastWriteTime)
1347 {
1348 FILE_BASIC_INFORMATION FileBasic;
1349 IO_STATUS_BLOCK IoStatusBlock;
1350 NTSTATUS Status;
1351
1352 if(IsConsoleHandle(hFile))
1353 {
1354 SetLastError(ERROR_INVALID_HANDLE);
1355 return FALSE;
1356 }
1357
1358 Status = NtQueryInformationFile(hFile,
1359 &IoStatusBlock,
1360 &FileBasic,
1361 sizeof(FILE_BASIC_INFORMATION),
1362 FileBasicInformation);
1363 if (!NT_SUCCESS(Status))
1364 {
1365 SetLastErrorByStatus(Status);
1366 return FALSE;
1367 }
1368
1369 if (lpCreationTime)
1370 memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
1371 if (lpLastAccessTime)
1372 memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
1373 if (lpLastWriteTime)
1374 memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
1375
1376 // should i initialize changetime ???
1377
1378 Status = NtSetInformationFile(hFile,
1379 &IoStatusBlock,
1380 &FileBasic,
1381 sizeof(FILE_BASIC_INFORMATION),
1382 FileBasicInformation);
1383 if (!NT_SUCCESS(Status))
1384 {
1385 SetLastErrorByStatus(Status);
1386 return FALSE;
1387 }
1388
1389 return TRUE;
1390 }
1391
1392
1393 /*
1394 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1395 *
1396 * @implemented
1397 */
1398 BOOL WINAPI
1399 SetEndOfFile(HANDLE hFile)
1400 {
1401 IO_STATUS_BLOCK IoStatusBlock;
1402 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1403 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1404 FILE_POSITION_INFORMATION FilePosInfo;
1405 NTSTATUS Status;
1406
1407 if(IsConsoleHandle(hFile))
1408 {
1409 SetLastError(ERROR_INVALID_HANDLE);
1410 return FALSE;
1411 }
1412
1413 //get current position
1414 Status = NtQueryInformationFile(
1415 hFile,
1416 &IoStatusBlock,
1417 &FilePosInfo,
1418 sizeof(FILE_POSITION_INFORMATION),
1419 FilePositionInformation
1420 );
1421
1422 if (!NT_SUCCESS(Status)){
1423 SetLastErrorByStatus(Status);
1424 return FALSE;
1425 }
1426
1427 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1428
1429 /*
1430 NOTE:
1431 This call is not supposed to free up any space after the eof marker
1432 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1433 But...most file systems dispatch both FileEndOfFileInformation
1434 and FileAllocationInformation as they were the same command.
1435
1436 */
1437 Status = NtSetInformationFile(
1438 hFile,
1439 &IoStatusBlock, //out
1440 &EndOfFileInfo,
1441 sizeof(FILE_END_OF_FILE_INFORMATION),
1442 FileEndOfFileInformation
1443 );
1444
1445 if (!NT_SUCCESS(Status)){
1446 SetLastErrorByStatus(Status);
1447 return FALSE;
1448 }
1449
1450 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1451
1452
1453 Status = NtSetInformationFile(
1454 hFile,
1455 &IoStatusBlock, //out
1456 &FileAllocationInfo,
1457 sizeof(FILE_ALLOCATION_INFORMATION),
1458 FileAllocationInformation
1459 );
1460
1461 if (!NT_SUCCESS(Status)){
1462 SetLastErrorByStatus(Status);
1463 return FALSE;
1464 }
1465
1466 return TRUE;
1467
1468 }
1469
1470
1471 /*
1472 * @implemented
1473 */
1474 BOOL
1475 WINAPI
1476 SetFileValidData(
1477 HANDLE hFile,
1478 LONGLONG ValidDataLength
1479 )
1480 {
1481 IO_STATUS_BLOCK IoStatusBlock;
1482 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1483 NTSTATUS Status;
1484
1485 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1486
1487 Status = NtSetInformationFile(
1488 hFile,
1489 &IoStatusBlock, //out
1490 &ValidDataLengthInformation,
1491 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1492 FileValidDataLengthInformation
1493 );
1494
1495 if (!NT_SUCCESS(Status)){
1496 SetLastErrorByStatus(Status);
1497 return FALSE;
1498 }
1499
1500 return TRUE;
1501 }
1502
1503
1504
1505 /*
1506 * @implemented
1507 */
1508 BOOL
1509 WINAPI
1510 SetFileShortNameW(
1511 HANDLE hFile,
1512 LPCWSTR lpShortName)
1513 {
1514 NTSTATUS Status;
1515 ULONG NeededSize;
1516 UNICODE_STRING ShortName;
1517 IO_STATUS_BLOCK IoStatusBlock;
1518 PFILE_NAME_INFORMATION FileNameInfo;
1519
1520 if(IsConsoleHandle(hFile))
1521 {
1522 SetLastError(ERROR_INVALID_HANDLE);
1523 return FALSE;
1524 }
1525
1526 if(!lpShortName)
1527 {
1528 SetLastError(ERROR_INVALID_PARAMETER);
1529 return FALSE;
1530 }
1531
1532 RtlInitUnicodeString(&ShortName, lpShortName);
1533
1534 NeededSize = sizeof(FILE_NAME_INFORMATION) + ShortName.Length + sizeof(WCHAR);
1535 if(!(FileNameInfo = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
1536 {
1537 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1538 return FALSE;
1539 }
1540
1541 FileNameInfo->FileNameLength = ShortName.Length;
1542 RtlCopyMemory(FileNameInfo->FileName, ShortName.Buffer, ShortName.Length);
1543
1544 Status = NtSetInformationFile(hFile,
1545 &IoStatusBlock, //out
1546 FileNameInfo,
1547 NeededSize,
1548 FileShortNameInformation);
1549
1550 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameInfo);
1551 if(!NT_SUCCESS(Status))
1552 {
1553 SetLastErrorByStatus(Status);
1554 return FALSE;
1555 }
1556
1557 return TRUE;
1558 }
1559
1560
1561 /*
1562 * @implemented
1563 */
1564 BOOL
1565 WINAPI
1566 SetFileShortNameA(
1567 HANDLE hFile,
1568 LPCSTR lpShortName
1569 )
1570 {
1571 PWCHAR ShortNameW;
1572
1573 if(IsConsoleHandle(hFile))
1574 {
1575 SetLastError(ERROR_INVALID_HANDLE);
1576 return FALSE;
1577 }
1578
1579 if(!lpShortName)
1580 {
1581 SetLastError(ERROR_INVALID_PARAMETER);
1582 return FALSE;
1583 }
1584
1585 if (!(ShortNameW = FilenameA2W(lpShortName, FALSE)))
1586 return FALSE;
1587
1588 return SetFileShortNameW(hFile, ShortNameW);
1589 }
1590
1591
1592 /*
1593 * @implemented
1594 */
1595 BOOL
1596 WINAPI
1597 CheckNameLegalDOS8Dot3W(
1598 LPCWSTR lpName,
1599 LPSTR lpOemName OPTIONAL,
1600 DWORD OemNameSize OPTIONAL,
1601 PBOOL pbNameContainsSpaces OPTIONAL,
1602 PBOOL pbNameLegal
1603 )
1604 {
1605 UNICODE_STRING Name;
1606 ANSI_STRING AnsiName;
1607
1608 if(lpName == NULL ||
1609 (lpOemName == NULL && OemNameSize != 0) ||
1610 pbNameLegal == NULL)
1611 {
1612 SetLastError(ERROR_INVALID_PARAMETER);
1613 return FALSE;
1614 }
1615
1616 if(lpOemName != NULL)
1617 {
1618 AnsiName.Buffer = lpOemName;
1619 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
1620 AnsiName.Length = 0;
1621 }
1622
1623 RtlInitUnicodeString(&Name, lpName);
1624
1625 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1626 (lpOemName ? &AnsiName : NULL),
1627 (BOOLEAN*)pbNameContainsSpaces);
1628
1629 return TRUE;
1630 }
1631
1632
1633 /*
1634 * @implemented
1635 */
1636 BOOL
1637 WINAPI
1638 CheckNameLegalDOS8Dot3A(
1639 LPCSTR lpName,
1640 LPSTR lpOemName OPTIONAL,
1641 DWORD OemNameSize OPTIONAL,
1642 PBOOL pbNameContainsSpaces OPTIONAL,
1643 PBOOL pbNameLegal
1644 )
1645 {
1646 UNICODE_STRING Name;
1647 ANSI_STRING AnsiName, AnsiInputName;
1648 NTSTATUS Status;
1649
1650 if(lpName == NULL ||
1651 (lpOemName == NULL && OemNameSize != 0) ||
1652 pbNameLegal == NULL)
1653 {
1654 SetLastError(ERROR_INVALID_PARAMETER);
1655 return FALSE;
1656 }
1657
1658 if(lpOemName != NULL)
1659 {
1660 AnsiName.Buffer = lpOemName;
1661 AnsiName.MaximumLength = (USHORT)OemNameSize * sizeof(CHAR);
1662 AnsiName.Length = 0;
1663 }
1664
1665 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
1666 if(bIsFileApiAnsi)
1667 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1668 else
1669 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1670
1671 if(!NT_SUCCESS(Status))
1672 {
1673 SetLastErrorByStatus(Status);
1674 return FALSE;
1675 }
1676
1677 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1678 (lpOemName ? &AnsiName : NULL),
1679 (BOOLEAN*)pbNameContainsSpaces);
1680
1681 RtlFreeUnicodeString(&Name);
1682
1683 return TRUE;
1684 }
1685
1686
1687 /*
1688 * @implemented
1689 */
1690 DWORD
1691 WINAPI
1692 GetFinalPathNameByHandleA(IN HANDLE hFile,
1693 OUT LPSTR lpszFilePath,
1694 IN DWORD cchFilePath,
1695 IN DWORD dwFlags)
1696 {
1697 WCHAR FilePathW[MAX_PATH];
1698 UNICODE_STRING FilePathU;
1699 DWORD PrevLastError;
1700 DWORD Ret = 0;
1701
1702 if (cchFilePath != 0 &&
1703 cchFilePath > sizeof(FilePathW) / sizeof(FilePathW[0]))
1704 {
1705 FilePathU.Length = 0;
1706 FilePathU.MaximumLength = (USHORT)cchFilePath * sizeof(WCHAR);
1707 FilePathU.Buffer = RtlAllocateHeap(RtlGetProcessHeap(),
1708 0,
1709 FilePathU.MaximumLength);
1710 if (FilePathU.Buffer == NULL)
1711 {
1712 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1713 return 0;
1714 }
1715 }
1716 else
1717 {
1718 FilePathU.Length = 0;
1719 FilePathU.MaximumLength = sizeof(FilePathW);
1720 FilePathU.Buffer = FilePathW;
1721 }
1722
1723 /* save the last error code */
1724 PrevLastError = GetLastError();
1725 SetLastError(ERROR_SUCCESS);
1726
1727 /* call the unicode version that does all the work */
1728 Ret = GetFinalPathNameByHandleW(hFile,
1729 FilePathU.Buffer,
1730 cchFilePath,
1731 dwFlags);
1732
1733 if (GetLastError() == ERROR_SUCCESS)
1734 {
1735 /* no error, restore the last error code and convert the string */
1736 SetLastError(PrevLastError);
1737
1738 Ret = FilenameU2A_FitOrFail(lpszFilePath,
1739 cchFilePath,
1740 &FilePathU);
1741 }
1742
1743 /* free allocated memory if necessary */
1744 if (FilePathU.Buffer != FilePathW)
1745 {
1746 RtlFreeHeap(RtlGetProcessHeap(),
1747 0,
1748 FilePathU.Buffer);
1749 }
1750
1751 return Ret;
1752 }
1753
1754
1755 /*
1756 * @unimplemented
1757 */
1758 DWORD
1759 WINAPI
1760 GetFinalPathNameByHandleW(IN HANDLE hFile,
1761 OUT LPWSTR lpszFilePath,
1762 IN DWORD cchFilePath,
1763 IN DWORD dwFlags)
1764 {
1765 if (dwFlags & ~(VOLUME_NAME_DOS | VOLUME_NAME_GUID | VOLUME_NAME_NT |
1766 VOLUME_NAME_NONE | FILE_NAME_NORMALIZED | FILE_NAME_OPENED))
1767 {
1768 SetLastError(ERROR_INVALID_PARAMETER);
1769 return 0;
1770 }
1771
1772 UNIMPLEMENTED;
1773 return 0;
1774 }
1775
1776
1777 /*
1778 * @unimplemented
1779 */
1780 BOOL
1781 WINAPI
1782 SetFileBandwidthReservation(IN HANDLE hFile,
1783 IN DWORD nPeriodMilliseconds,
1784 IN DWORD nBytesPerPeriod,
1785 IN BOOL bDiscardable,
1786 OUT LPDWORD lpTransferSize,
1787 OUT LPDWORD lpNumOutstandingRequests)
1788 {
1789 UNIMPLEMENTED;
1790 return FALSE;
1791 }
1792
1793
1794 /*
1795 * @unimplemented
1796 */
1797 BOOL
1798 WINAPI
1799 GetFileBandwidthReservation(IN HANDLE hFile,
1800 OUT LPDWORD lpPeriodMilliseconds,
1801 OUT LPDWORD lpBytesPerPeriod,
1802 OUT LPBOOL pDiscardable,
1803 OUT LPDWORD lpTransferSize,
1804 OUT LPDWORD lpNumOutstandingRequests)
1805 {
1806 UNIMPLEMENTED;
1807 return FALSE;
1808 }
1809
1810
1811 /*
1812 * @unimplemented
1813 */
1814 BOOL
1815 WINAPI
1816 SetFileCompletionNotificationModes(IN HANDLE FileHandle,
1817 IN UCHAR Flags)
1818 {
1819 if (Flags & ~(FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | FILE_SKIP_SET_EVENT_ON_HANDLE))
1820 {
1821 SetLastError(ERROR_INVALID_PARAMETER);
1822 return FALSE;
1823 }
1824
1825 UNIMPLEMENTED;
1826 return FALSE;
1827 }
1828
1829
1830 /*
1831 * @unimplemented
1832 */
1833 HANDLE
1834 WINAPI
1835 OpenFileById(IN HANDLE hFile,
1836 IN LPFILE_ID_DESCRIPTOR lpFileID,
1837 IN DWORD dwDesiredAccess,
1838 IN DWORD dwShareMode,
1839 IN LPSECURITY_ATTRIBUTES lpSecurityAttributes OPTIONAL,
1840 IN DWORD dwFlags)
1841 {
1842 UNIMPLEMENTED;
1843 return INVALID_HANDLE_VALUE;
1844 }
1845
1846 /*
1847 * @implemented
1848 */
1849 BOOL
1850 WINAPI
1851 ReplaceFileA(
1852 LPCSTR lpReplacedFileName,
1853 LPCSTR lpReplacementFileName,
1854 LPCSTR lpBackupFileName,
1855 DWORD dwReplaceFlags,
1856 LPVOID lpExclude,
1857 LPVOID lpReserved
1858 )
1859 {
1860 WCHAR *replacedW, *replacementW, *backupW = NULL;
1861 BOOL ret;
1862
1863 /* This function only makes sense when the first two parameters are defined */
1864 if (!lpReplacedFileName || !(replacedW = FilenameA2W(lpReplacedFileName, TRUE)))
1865 {
1866 SetLastError(ERROR_INVALID_PARAMETER);
1867 return FALSE;
1868 }
1869
1870 if (!lpReplacementFileName || !(replacementW = FilenameA2W(lpReplacementFileName, TRUE)))
1871 {
1872 HeapFree(GetProcessHeap(), 0, replacedW);
1873 SetLastError(ERROR_INVALID_PARAMETER);
1874 return FALSE;
1875 }
1876
1877 /* The backup parameter, however, is optional */
1878 if (lpBackupFileName)
1879 {
1880 if (!(backupW = FilenameA2W(lpBackupFileName, TRUE)))
1881 {
1882 HeapFree(GetProcessHeap(), 0, replacedW);
1883 HeapFree(GetProcessHeap(), 0, replacementW);
1884 SetLastError(ERROR_INVALID_PARAMETER);
1885 return FALSE;
1886 }
1887 }
1888
1889 ret = ReplaceFileW(replacedW, replacementW, backupW, dwReplaceFlags, lpExclude, lpReserved);
1890 HeapFree(GetProcessHeap(), 0, replacedW);
1891 HeapFree(GetProcessHeap(), 0, replacementW);
1892 HeapFree(GetProcessHeap(), 0, backupW);
1893
1894 return ret;
1895 }
1896
1897 /*
1898 * @unimplemented
1899 */
1900 BOOL
1901 WINAPI
1902 ReplaceFileW(
1903 LPCWSTR lpReplacedFileName,
1904 LPCWSTR lpReplacementFileName,
1905 LPCWSTR lpBackupFileName,
1906 DWORD dwReplaceFlags,
1907 LPVOID lpExclude,
1908 LPVOID lpReserved
1909 )
1910 {
1911 HANDLE hReplaced = NULL, hReplacement = NULL;
1912 UNICODE_STRING NtReplacedName = { 0, 0, NULL };
1913 UNICODE_STRING NtReplacementName = { 0, 0, NULL };
1914 DWORD Error = ERROR_SUCCESS;
1915 NTSTATUS Status;
1916 BOOL Ret = FALSE;
1917 IO_STATUS_BLOCK IoStatusBlock;
1918 OBJECT_ATTRIBUTES ObjectAttributes;
1919 PVOID Buffer = NULL ;
1920
1921 if (dwReplaceFlags)
1922 FIXME("Ignoring flags %x\n", dwReplaceFlags);
1923
1924 /* First two arguments are mandatory */
1925 if (!lpReplacedFileName || !lpReplacementFileName)
1926 {
1927 SetLastError(ERROR_INVALID_PARAMETER);
1928 return FALSE;
1929 }
1930
1931 /* Back it up */
1932 if(lpBackupFileName)
1933 {
1934 if(!CopyFileW(lpReplacedFileName, lpBackupFileName, FALSE))
1935 {
1936 Error = GetLastError();
1937 goto Cleanup ;
1938 }
1939 }
1940
1941 /* Open the "replaced" file for reading and writing */
1942 if (!(RtlDosPathNameToNtPathName_U(lpReplacedFileName, &NtReplacedName, NULL, NULL)))
1943 {
1944 Error = ERROR_PATH_NOT_FOUND;
1945 goto Cleanup;
1946 }
1947
1948 InitializeObjectAttributes(&ObjectAttributes,
1949 &NtReplacedName,
1950 OBJ_CASE_INSENSITIVE,
1951 NULL,
1952 NULL);
1953
1954 Status = NtOpenFile(&hReplaced,
1955 GENERIC_READ | GENERIC_WRITE | DELETE | SYNCHRONIZE | WRITE_DAC,
1956 &ObjectAttributes,
1957 &IoStatusBlock,
1958 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1959 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
1960
1961 if (!NT_SUCCESS(Status))
1962 {
1963 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
1964 Error = ERROR_FILE_NOT_FOUND;
1965 else
1966 Error = ERROR_UNABLE_TO_REMOVE_REPLACED;
1967 goto Cleanup;
1968 }
1969
1970 /* Blank it */
1971 SetEndOfFile(hReplaced) ;
1972
1973 /*
1974 * Open the replacement file for reading, writing, and deleting
1975 * (deleting is needed when finished)
1976 */
1977 if (!(RtlDosPathNameToNtPathName_U(lpReplacementFileName, &NtReplacementName, NULL, NULL)))
1978 {
1979 Error = ERROR_PATH_NOT_FOUND;
1980 goto Cleanup;
1981 }
1982
1983 InitializeObjectAttributes(&ObjectAttributes,
1984 &NtReplacementName,
1985 OBJ_CASE_INSENSITIVE,
1986 NULL,
1987 NULL);
1988
1989 Status = NtOpenFile(&hReplacement,
1990 GENERIC_READ | DELETE | SYNCHRONIZE,
1991 &ObjectAttributes,
1992 &IoStatusBlock,
1993 0,
1994 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE);
1995
1996 if (!NT_SUCCESS(Status))
1997 {
1998 Error = RtlNtStatusToDosError(Status);
1999 goto Cleanup;
2000 }
2001
2002 Buffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, 0x10000) ;
2003 if (!Buffer)
2004 {
2005 Error = ERROR_NOT_ENOUGH_MEMORY;
2006 goto Cleanup ;
2007 }
2008 while (Status != STATUS_END_OF_FILE)
2009 {
2010 Status = NtReadFile(hReplacement, NULL, NULL, NULL, &IoStatusBlock, Buffer, 0x10000, NULL, NULL) ;
2011 if (NT_SUCCESS(Status))
2012 {
2013 Status = NtWriteFile(hReplaced, NULL, NULL, NULL, &IoStatusBlock, Buffer,
2014 IoStatusBlock.Information, NULL, NULL) ;
2015 if (!NT_SUCCESS(Status))
2016 {
2017 Error = RtlNtStatusToDosError(Status);
2018 goto Cleanup;
2019 }
2020 }
2021 else if (Status != STATUS_END_OF_FILE)
2022 {
2023 Error = RtlNtStatusToDosError(Status);
2024 goto Cleanup;
2025 }
2026 }
2027
2028 Ret = TRUE;
2029
2030 /* Perform resource cleanup */
2031 Cleanup:
2032 if (hReplaced) NtClose(hReplaced);
2033 if (hReplacement) NtClose(hReplacement);
2034 if (Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Buffer);
2035
2036 if (NtReplacementName.Buffer)
2037 RtlFreeHeap(GetProcessHeap(), 0, NtReplacementName.Buffer);
2038 if (NtReplacedName.Buffer)
2039 RtlFreeHeap(GetProcessHeap(), 0, NtReplacedName.Buffer);
2040
2041 /* If there was an error, set the error code */
2042 if(!Ret)
2043 {
2044 TRACE("ReplaceFileW failed (error=%d)\n", Error);
2045 SetLastError(Error);
2046 }
2047 return Ret;
2048 }
2049
2050 /* EOF */