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