[FFS] Don't leak on failure
[reactos.git] / dll / win32 / kernel32 / client / file / fileinfo.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: dll/win32/kernel32/client/file/fileinfo.c
5 * PURPOSE: Directory functions
6 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
7 * Pierre Schweitzer (pierre.schweitzer@reactos.org)
8 * UPDATE HISTORY:
9 * Created 01/11/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <k32.h>
15 #define NDEBUG
16 #include <debug.h>
17 DEBUG_CHANNEL(kernel32file);
18
19 /* FUNCTIONS ****************************************************************/
20
21 PWCHAR
22 FilenameA2W(LPCSTR NameA, BOOL alloc)
23 {
24 ANSI_STRING str;
25 UNICODE_STRING strW;
26 PUNICODE_STRING pstrW;
27 NTSTATUS Status;
28
29 //ASSERT(NtCurrentTeb()->StaticUnicodeString.Buffer == NtCurrentTeb()->StaticUnicodeBuffer);
30 ASSERT(NtCurrentTeb()->StaticUnicodeString.MaximumLength == sizeof(NtCurrentTeb()->StaticUnicodeBuffer));
31
32 RtlInitAnsiString(&str, NameA);
33 pstrW = alloc ? &strW : &NtCurrentTeb()->StaticUnicodeString;
34
35 if (bIsFileApiAnsi)
36 Status= RtlAnsiStringToUnicodeString( pstrW, &str, (BOOLEAN)alloc );
37 else
38 Status= RtlOemStringToUnicodeString( pstrW, &str, (BOOLEAN)alloc );
39
40 if (NT_SUCCESS(Status))
41 return pstrW->Buffer;
42
43 if (Status== STATUS_BUFFER_OVERFLOW)
44 SetLastError( ERROR_FILENAME_EXCED_RANGE );
45 else
46 BaseSetLastNTError(Status);
47
48 return NULL;
49 }
50
51
52 /*
53 No copy/conversion is done if the dest. buffer is too small.
54
55 Returns:
56 Success: number of TCHARS copied into dest. buffer NOT including nullterm
57 Fail: size of buffer in TCHARS required to hold the converted filename, including nullterm
58 */
59 DWORD
60 FilenameU2A_FitOrFail(
61 LPSTR DestA,
62 INT destLen, /* buffer size in TCHARS incl. nullchar */
63 PUNICODE_STRING SourceU
64 )
65 {
66 DWORD ret;
67
68 /* destLen should never exceed MAX_PATH */
69 if (destLen > MAX_PATH) destLen = MAX_PATH;
70
71 ret = bIsFileApiAnsi? RtlUnicodeStringToAnsiSize(SourceU) : RtlUnicodeStringToOemSize(SourceU);
72 /* ret incl. nullchar */
73
74 if (DestA && (INT)ret <= destLen)
75 {
76 ANSI_STRING str;
77
78 str.Buffer = DestA;
79 str.MaximumLength = (USHORT)destLen;
80
81
82 if (bIsFileApiAnsi)
83 RtlUnicodeStringToAnsiString(&str, SourceU, FALSE );
84 else
85 RtlUnicodeStringToOemString(&str, SourceU, FALSE );
86
87 ret = str.Length; /* SUCCESS: length without terminating 0 */
88 }
89
90 return ret;
91 }
92
93
94 /*
95 No copy/conversion is done if the dest. buffer is too small.
96
97 Returns:
98 Success: number of TCHARS copied into dest. buffer NOT including nullterm
99 Fail: size of buffer in TCHARS required to hold the converted filename, including nullterm
100 */
101 DWORD
102 FilenameW2A_FitOrFail(
103 LPSTR DestA,
104 INT destLen, /* buffer size in TCHARS incl. nullchar */
105 LPCWSTR SourceW,
106 INT sourceLen /* buffer size in TCHARS incl. nullchar */
107 )
108 {
109 UNICODE_STRING strW;
110
111 if (sourceLen < 0) sourceLen = wcslen(SourceW) + 1;
112
113 strW.Buffer = (PWCHAR)SourceW;
114 strW.MaximumLength = sourceLen * sizeof(WCHAR);
115 strW.Length = strW.MaximumLength - sizeof(WCHAR);
116
117 return FilenameU2A_FitOrFail(DestA, destLen, &strW);
118 }
119
120
121 /*
122 Return: num. TCHARS copied into dest including nullterm
123 */
124 DWORD
125 FilenameA2W_N(
126 LPWSTR dest,
127 INT destlen, /* buffer size in TCHARS incl. nullchar */
128 LPCSTR src,
129 INT srclen /* buffer size in TCHARS incl. nullchar */
130 )
131 {
132 DWORD ret;
133
134 if (srclen < 0) srclen = strlen( src ) + 1;
135
136 if (bIsFileApiAnsi)
137 RtlMultiByteToUnicodeN( dest, destlen* sizeof(WCHAR), &ret, (LPSTR)src, srclen );
138 else
139 RtlOemToUnicodeN( dest, destlen* sizeof(WCHAR), &ret, (LPSTR)src, srclen );
140
141 if (ret) dest[(ret/sizeof(WCHAR))-1]=0;
142
143 return ret/sizeof(WCHAR);
144 }
145
146 /*
147 Return: num. TCHARS copied into dest including nullterm
148 */
149 DWORD
150 FilenameW2A_N(
151 LPSTR dest,
152 INT destlen, /* buffer size in TCHARS incl. nullchar */
153 LPCWSTR src,
154 INT srclen /* buffer size in TCHARS incl. nullchar */
155 )
156 {
157 DWORD ret;
158
159 if (srclen < 0) srclen = wcslen( src ) + 1;
160
161 if (bIsFileApiAnsi)
162 RtlUnicodeToMultiByteN( dest, destlen, &ret, (LPWSTR) src, srclen * sizeof(WCHAR));
163 else
164 RtlUnicodeToOemN( dest, destlen, &ret, (LPWSTR) src, srclen * sizeof(WCHAR) );
165
166 if (ret) dest[ret-1]=0;
167
168 return ret;
169 }
170
171 /*
172 * @implemented
173 */
174 BOOL WINAPI
175 FlushFileBuffers(IN HANDLE hFile)
176 {
177 NTSTATUS Status;
178 IO_STATUS_BLOCK IoStatusBlock;
179
180 hFile = TranslateStdHandle(hFile);
181
182 if (IsConsoleHandle(hFile))
183 {
184 return FlushConsoleInputBuffer(hFile);
185 }
186
187 Status = NtFlushBuffersFile(hFile,
188 &IoStatusBlock);
189 if (!NT_SUCCESS(Status))
190 {
191 BaseSetLastNTError(Status);
192 return FALSE;
193 }
194 return TRUE;
195 }
196
197
198 /*
199 * @implemented
200 */
201 DWORD
202 WINAPI
203 DECLSPEC_HOTPATCH
204 SetFilePointer(HANDLE hFile,
205 LONG lDistanceToMove,
206 PLONG lpDistanceToMoveHigh,
207 DWORD dwMoveMethod)
208 {
209 FILE_POSITION_INFORMATION FilePosition;
210 FILE_STANDARD_INFORMATION FileStandard;
211 NTSTATUS errCode;
212 IO_STATUS_BLOCK IoStatusBlock;
213 LARGE_INTEGER Distance;
214
215 TRACE("SetFilePointer(hFile %p, lDistanceToMove %d, dwMoveMethod %lu)\n",
216 hFile,lDistanceToMove,dwMoveMethod);
217
218 if(IsConsoleHandle(hFile))
219 {
220 SetLastError(ERROR_INVALID_HANDLE);
221 return INVALID_SET_FILE_POINTER;
222 }
223
224 if (lpDistanceToMoveHigh)
225 {
226 Distance.u.HighPart = *lpDistanceToMoveHigh;
227 Distance.u.LowPart = lDistanceToMove;
228 }
229 else
230 {
231 Distance.QuadPart = lDistanceToMove;
232 }
233
234 switch(dwMoveMethod)
235 {
236 case FILE_CURRENT:
237 errCode = NtQueryInformationFile(hFile,
238 &IoStatusBlock,
239 &FilePosition,
240 sizeof(FILE_POSITION_INFORMATION),
241 FilePositionInformation);
242 FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
243 if (!NT_SUCCESS(errCode))
244 {
245 if (lpDistanceToMoveHigh != NULL)
246 *lpDistanceToMoveHigh = -1;
247 BaseSetLastNTError(errCode);
248 return INVALID_SET_FILE_POINTER;
249 }
250 break;
251 case FILE_END:
252 errCode = NtQueryInformationFile(hFile,
253 &IoStatusBlock,
254 &FileStandard,
255 sizeof(FILE_STANDARD_INFORMATION),
256 FileStandardInformation);
257 FilePosition.CurrentByteOffset.QuadPart =
258 FileStandard.EndOfFile.QuadPart + Distance.QuadPart;
259 if (!NT_SUCCESS(errCode))
260 {
261 if (lpDistanceToMoveHigh != NULL)
262 *lpDistanceToMoveHigh = -1;
263 BaseSetLastNTError(errCode);
264 return INVALID_SET_FILE_POINTER;
265 }
266 break;
267 case FILE_BEGIN:
268 FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
269 break;
270 default:
271 SetLastError(ERROR_INVALID_PARAMETER);
272 return INVALID_SET_FILE_POINTER;
273 }
274
275 if(FilePosition.CurrentByteOffset.QuadPart < 0)
276 {
277 SetLastError(ERROR_NEGATIVE_SEEK);
278 return INVALID_SET_FILE_POINTER;
279 }
280
281 if (lpDistanceToMoveHigh == NULL && FilePosition.CurrentByteOffset.HighPart != 0)
282 {
283 /* If we're moving the pointer outside of the 32 bit boundaries but
284 the application only passed a 32 bit value we need to bail out! */
285 SetLastError(ERROR_INVALID_PARAMETER);
286 return INVALID_SET_FILE_POINTER;
287 }
288
289 errCode = NtSetInformationFile(hFile,
290 &IoStatusBlock,
291 &FilePosition,
292 sizeof(FILE_POSITION_INFORMATION),
293 FilePositionInformation);
294 if (!NT_SUCCESS(errCode))
295 {
296 if (lpDistanceToMoveHigh != NULL)
297 *lpDistanceToMoveHigh = -1;
298
299 BaseSetLastNTError(errCode);
300 return INVALID_SET_FILE_POINTER;
301 }
302
303 if (lpDistanceToMoveHigh != NULL)
304 {
305 *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
306 }
307
308 if (FilePosition.CurrentByteOffset.u.LowPart == MAXDWORD)
309 {
310 /* The value of -1 is valid here, especially when the new
311 file position is greater than 4 GB. Since NtSetInformationFile
312 succeeded we never set an error code and we explicitly need
313 to clear a previously set error code in this case, which
314 an application will check if INVALID_SET_FILE_POINTER is returned! */
315 SetLastError(ERROR_SUCCESS);
316 }
317
318 return FilePosition.CurrentByteOffset.u.LowPart;
319 }
320
321
322 /*
323 * @implemented
324 */
325 BOOL
326 WINAPI
327 SetFilePointerEx(HANDLE hFile,
328 LARGE_INTEGER liDistanceToMove,
329 PLARGE_INTEGER lpNewFilePointer,
330 DWORD dwMoveMethod)
331 {
332 FILE_POSITION_INFORMATION FilePosition;
333 FILE_STANDARD_INFORMATION FileStandard;
334 NTSTATUS errCode;
335 IO_STATUS_BLOCK IoStatusBlock;
336
337 if(IsConsoleHandle(hFile))
338 {
339 SetLastError(ERROR_INVALID_HANDLE);
340 return FALSE;
341 }
342
343 switch(dwMoveMethod)
344 {
345 case FILE_CURRENT:
346 NtQueryInformationFile(hFile,
347 &IoStatusBlock,
348 &FilePosition,
349 sizeof(FILE_POSITION_INFORMATION),
350 FilePositionInformation);
351 FilePosition.CurrentByteOffset.QuadPart += liDistanceToMove.QuadPart;
352 break;
353 case FILE_END:
354 NtQueryInformationFile(hFile,
355 &IoStatusBlock,
356 &FileStandard,
357 sizeof(FILE_STANDARD_INFORMATION),
358 FileStandardInformation);
359 FilePosition.CurrentByteOffset.QuadPart =
360 FileStandard.EndOfFile.QuadPart + liDistanceToMove.QuadPart;
361 break;
362 case FILE_BEGIN:
363 FilePosition.CurrentByteOffset.QuadPart = liDistanceToMove.QuadPart;
364 break;
365 default:
366 SetLastError(ERROR_INVALID_PARAMETER);
367 return FALSE;
368 }
369
370 if(FilePosition.CurrentByteOffset.QuadPart < 0)
371 {
372 SetLastError(ERROR_NEGATIVE_SEEK);
373 return FALSE;
374 }
375
376 errCode = NtSetInformationFile(hFile,
377 &IoStatusBlock,
378 &FilePosition,
379 sizeof(FILE_POSITION_INFORMATION),
380 FilePositionInformation);
381 if (!NT_SUCCESS(errCode))
382 {
383 BaseSetLastNTError(errCode);
384 return FALSE;
385 }
386
387 if (lpNewFilePointer)
388 {
389 *lpNewFilePointer = FilePosition.CurrentByteOffset;
390 }
391 return TRUE;
392 }
393
394
395 /*
396 * @implemented
397 */
398 DWORD WINAPI
399 GetFileType(HANDLE hFile)
400 {
401 FILE_FS_DEVICE_INFORMATION DeviceInfo;
402 IO_STATUS_BLOCK StatusBlock;
403 NTSTATUS Status;
404
405 /* Get real handle */
406 hFile = TranslateStdHandle(hFile);
407
408 /* Check for console handle */
409 if (IsConsoleHandle(hFile))
410 {
411 if (VerifyConsoleIoHandle(hFile))
412 return FILE_TYPE_CHAR;
413 }
414
415 Status = NtQueryVolumeInformationFile(hFile,
416 &StatusBlock,
417 &DeviceInfo,
418 sizeof(FILE_FS_DEVICE_INFORMATION),
419 FileFsDeviceInformation);
420 if (!NT_SUCCESS(Status))
421 {
422 BaseSetLastNTError(Status);
423 return FILE_TYPE_UNKNOWN;
424 }
425
426 switch (DeviceInfo.DeviceType)
427 {
428 case FILE_DEVICE_CD_ROM:
429 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
430 case FILE_DEVICE_CONTROLLER:
431 case FILE_DEVICE_DATALINK:
432 case FILE_DEVICE_DFS:
433 case FILE_DEVICE_DISK:
434 case FILE_DEVICE_DISK_FILE_SYSTEM:
435 case FILE_DEVICE_VIRTUAL_DISK:
436 return FILE_TYPE_DISK;
437
438 case FILE_DEVICE_KEYBOARD:
439 case FILE_DEVICE_MOUSE:
440 case FILE_DEVICE_NULL:
441 case FILE_DEVICE_PARALLEL_PORT:
442 case FILE_DEVICE_PRINTER:
443 case FILE_DEVICE_SERIAL_PORT:
444 case FILE_DEVICE_SCREEN:
445 case FILE_DEVICE_SOUND:
446 case FILE_DEVICE_MODEM:
447 return FILE_TYPE_CHAR;
448
449 case FILE_DEVICE_NAMED_PIPE:
450 return FILE_TYPE_PIPE;
451 }
452
453 return FILE_TYPE_UNKNOWN;
454 }
455
456
457 /*
458 * @implemented
459 */
460 DWORD WINAPI
461 GetFileSize(HANDLE hFile,
462 LPDWORD lpFileSizeHigh)
463 {
464 NTSTATUS errCode;
465 FILE_STANDARD_INFORMATION FileStandard;
466 IO_STATUS_BLOCK IoStatusBlock;
467
468 errCode = NtQueryInformationFile(hFile,
469 &IoStatusBlock,
470 &FileStandard,
471 sizeof(FILE_STANDARD_INFORMATION),
472 FileStandardInformation);
473 if (!NT_SUCCESS(errCode))
474 {
475 BaseSetLastNTError(errCode);
476 if ( lpFileSizeHigh == NULL )
477 {
478 return -1;
479 }
480 else
481 {
482 return 0;
483 }
484 }
485 if ( lpFileSizeHigh != NULL )
486 *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
487
488 return FileStandard.EndOfFile.u.LowPart;
489 }
490
491
492 /*
493 * @implemented
494 */
495 BOOL
496 WINAPI
497 GetFileSizeEx(
498 HANDLE hFile,
499 PLARGE_INTEGER lpFileSize
500 )
501 {
502 NTSTATUS errCode;
503 FILE_STANDARD_INFORMATION FileStandard;
504 IO_STATUS_BLOCK IoStatusBlock;
505
506 errCode = NtQueryInformationFile(hFile,
507 &IoStatusBlock,
508 &FileStandard,
509 sizeof(FILE_STANDARD_INFORMATION),
510 FileStandardInformation);
511 if (!NT_SUCCESS(errCode))
512 {
513 BaseSetLastNTError(errCode);
514 return FALSE;
515 }
516 if (lpFileSize)
517 *lpFileSize = FileStandard.EndOfFile;
518
519 return TRUE;
520 }
521
522
523 /*
524 * @implemented
525 */
526 DWORD WINAPI
527 GetCompressedFileSizeA(LPCSTR lpFileName,
528 LPDWORD lpFileSizeHigh)
529 {
530 PWCHAR FileNameW;
531
532 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
533 return INVALID_FILE_SIZE;
534
535 return GetCompressedFileSizeW(FileNameW, lpFileSizeHigh);
536 }
537
538
539 /*
540 * @implemented
541 */
542 DWORD WINAPI
543 GetCompressedFileSizeW(LPCWSTR lpFileName,
544 LPDWORD lpFileSizeHigh)
545 {
546 FILE_COMPRESSION_INFORMATION FileCompression;
547 NTSTATUS errCode;
548 IO_STATUS_BLOCK IoStatusBlock;
549 HANDLE hFile;
550
551 hFile = CreateFileW(lpFileName,
552 GENERIC_READ,
553 FILE_SHARE_READ,
554 NULL,
555 OPEN_EXISTING,
556 FILE_ATTRIBUTE_NORMAL,
557 NULL);
558
559 if (hFile == INVALID_HANDLE_VALUE)
560 return INVALID_FILE_SIZE;
561
562 errCode = NtQueryInformationFile(hFile,
563 &IoStatusBlock,
564 &FileCompression,
565 sizeof(FILE_COMPRESSION_INFORMATION),
566 FileCompressionInformation);
567
568 CloseHandle(hFile);
569
570 if (!NT_SUCCESS(errCode))
571 {
572 BaseSetLastNTError(errCode);
573 return INVALID_FILE_SIZE;
574 }
575
576 if(lpFileSizeHigh)
577 *lpFileSizeHigh = FileCompression.CompressedFileSize.u.HighPart;
578
579 SetLastError(NO_ERROR);
580 return FileCompression.CompressedFileSize.u.LowPart;
581 }
582
583
584 /*
585 * @implemented
586 */
587 BOOL WINAPI
588 GetFileInformationByHandle(HANDLE hFile,
589 LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
590 {
591 struct
592 {
593 FILE_FS_VOLUME_INFORMATION FileFsVolume;
594 WCHAR Name[255];
595 }
596 FileFsVolume;
597
598 FILE_BASIC_INFORMATION FileBasic;
599 FILE_INTERNAL_INFORMATION FileInternal;
600 FILE_STANDARD_INFORMATION FileStandard;
601 NTSTATUS errCode;
602 IO_STATUS_BLOCK IoStatusBlock;
603
604 if(IsConsoleHandle(hFile))
605 {
606 SetLastError(ERROR_INVALID_HANDLE);
607 return FALSE;
608 }
609
610 errCode = NtQueryInformationFile(hFile,
611 &IoStatusBlock,
612 &FileBasic,
613 sizeof(FILE_BASIC_INFORMATION),
614 FileBasicInformation);
615 if (!NT_SUCCESS(errCode))
616 {
617 BaseSetLastNTError(errCode);
618 return FALSE;
619 }
620
621 lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes;
622
623 lpFileInformation->ftCreationTime.dwHighDateTime = FileBasic.CreationTime.u.HighPart;
624 lpFileInformation->ftCreationTime.dwLowDateTime = FileBasic.CreationTime.u.LowPart;
625
626 lpFileInformation->ftLastAccessTime.dwHighDateTime = FileBasic.LastAccessTime.u.HighPart;
627 lpFileInformation->ftLastAccessTime.dwLowDateTime = FileBasic.LastAccessTime.u.LowPart;
628
629 lpFileInformation->ftLastWriteTime.dwHighDateTime = FileBasic.LastWriteTime.u.HighPart;
630 lpFileInformation->ftLastWriteTime.dwLowDateTime = FileBasic.LastWriteTime.u.LowPart;
631
632 errCode = NtQueryInformationFile(hFile,
633 &IoStatusBlock,
634 &FileInternal,
635 sizeof(FILE_INTERNAL_INFORMATION),
636 FileInternalInformation);
637 if (!NT_SUCCESS(errCode))
638 {
639 BaseSetLastNTError(errCode);
640 return FALSE;
641 }
642
643 lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart;
644 lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart;
645
646 errCode = NtQueryVolumeInformationFile(hFile,
647 &IoStatusBlock,
648 &FileFsVolume,
649 sizeof(FileFsVolume),
650 FileFsVolumeInformation);
651 if (!NT_SUCCESS(errCode))
652 {
653 BaseSetLastNTError(errCode);
654 return FALSE;
655 }
656
657 lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber;
658
659 errCode = NtQueryInformationFile(hFile,
660 &IoStatusBlock,
661 &FileStandard,
662 sizeof(FILE_STANDARD_INFORMATION),
663 FileStandardInformation);
664 if (!NT_SUCCESS(errCode))
665 {
666 BaseSetLastNTError(errCode);
667 return FALSE;
668 }
669
670 lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks;
671 lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
672 lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart;
673
674 return TRUE;
675 }
676
677
678 /*
679 * @implemented
680 */
681 BOOL WINAPI
682 GetFileAttributesExW(LPCWSTR lpFileName,
683 GET_FILEEX_INFO_LEVELS fInfoLevelId,
684 LPVOID lpFileInformation)
685 {
686 FILE_NETWORK_OPEN_INFORMATION FileInformation;
687 OBJECT_ATTRIBUTES ObjectAttributes;
688 UNICODE_STRING FileName;
689 NTSTATUS Status;
690 WIN32_FILE_ATTRIBUTE_DATA* FileAttributeData;
691
692 TRACE("GetFileAttributesExW(%S) called\n", lpFileName);
693
694
695 if (fInfoLevelId != GetFileExInfoStandard || lpFileInformation == NULL)
696 {
697 SetLastError(ERROR_INVALID_PARAMETER);
698 return FALSE;
699 }
700
701 /* Validate and translate the filename */
702 if (!RtlDosPathNameToNtPathName_U (lpFileName,
703 &FileName,
704 NULL,
705 NULL))
706 {
707 WARN ("Invalid path '%S'\n", lpFileName);
708 SetLastError (ERROR_BAD_PATHNAME);
709 return FALSE;
710 }
711
712 /* build the object attributes */
713 InitializeObjectAttributes (&ObjectAttributes,
714 &FileName,
715 OBJ_CASE_INSENSITIVE,
716 NULL,
717 NULL);
718
719 /* Get file attributes */
720 Status = NtQueryFullAttributesFile(&ObjectAttributes,
721 &FileInformation);
722
723 RtlFreeUnicodeString (&FileName);
724 if (!NT_SUCCESS (Status))
725 {
726 WARN ("NtQueryFullAttributesFile() failed (Status %lx)\n", Status);
727 BaseSetLastNTError (Status);
728 return FALSE;
729 }
730
731 FileAttributeData = (WIN32_FILE_ATTRIBUTE_DATA*)lpFileInformation;
732 FileAttributeData->dwFileAttributes = FileInformation.FileAttributes;
733 FileAttributeData->ftCreationTime.dwLowDateTime = FileInformation.CreationTime.u.LowPart;
734 FileAttributeData->ftCreationTime.dwHighDateTime = FileInformation.CreationTime.u.HighPart;
735 FileAttributeData->ftLastAccessTime.dwLowDateTime = FileInformation.LastAccessTime.u.LowPart;
736 FileAttributeData->ftLastAccessTime.dwHighDateTime = FileInformation.LastAccessTime.u.HighPart;
737 FileAttributeData->ftLastWriteTime.dwLowDateTime = FileInformation.LastWriteTime.u.LowPart;
738 FileAttributeData->ftLastWriteTime.dwHighDateTime = FileInformation.LastWriteTime.u.HighPart;
739 FileAttributeData->nFileSizeLow = FileInformation.EndOfFile.u.LowPart;
740 FileAttributeData->nFileSizeHigh = FileInformation.EndOfFile.u.HighPart;
741
742 return TRUE;
743 }
744
745 /*
746 * @implemented
747 */
748 BOOL WINAPI
749 GetFileAttributesExA(LPCSTR lpFileName,
750 GET_FILEEX_INFO_LEVELS fInfoLevelId,
751 LPVOID lpFileInformation)
752 {
753 PWCHAR FileNameW;
754
755 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
756 return FALSE;
757
758 return GetFileAttributesExW(FileNameW, fInfoLevelId, lpFileInformation);
759 }
760
761
762 /*
763 * @implemented
764 */
765 DWORD WINAPI
766 GetFileAttributesA(LPCSTR lpFileName)
767 {
768 PWSTR FileNameW;
769
770 if (!lpFileName || !(FileNameW = FilenameA2W(lpFileName, FALSE)))
771 return INVALID_FILE_ATTRIBUTES;
772
773 return GetFileAttributesW(FileNameW);
774 }
775
776
777 /*
778 * @implemented
779 */
780 DWORD
781 WINAPI
782 GetFileAttributesW(LPCWSTR lpFileName)
783 {
784 NTSTATUS Status;
785 UNICODE_STRING FileName;
786 OBJECT_ATTRIBUTES ObjectAttributes;
787 FILE_BASIC_INFORMATION FileInformation;
788
789 /* Get the NT path name */
790 if (!RtlDosPathNameToNtPathName_U(lpFileName, &FileName, NULL, NULL))
791 {
792 SetLastError(ERROR_PATH_NOT_FOUND);
793 return INVALID_FILE_ATTRIBUTES;
794 }
795
796 /* Prepare for querying attributes */
797 InitializeObjectAttributes(&ObjectAttributes, &FileName,
798 OBJ_CASE_INSENSITIVE,
799 NULL, NULL);
800 /* Simply query attributes */
801 Status = NtQueryAttributesFile(&ObjectAttributes, &FileInformation);
802 if (!NT_SUCCESS(Status))
803 {
804 /* It failed? Is it a DOS device? */
805 if (RtlIsDosDeviceName_U(lpFileName))
806 {
807 return FILE_ATTRIBUTE_ARCHIVE;
808 }
809
810 /* Set the error otherwise */
811 BaseSetLastNTError(Status);
812 return INVALID_FILE_ATTRIBUTES;
813 }
814
815 /* Return the file attributes */
816 return FileInformation.FileAttributes;
817 }
818
819
820 /*
821 * @implemented
822 */
823 BOOL WINAPI
824 GetFileAttributesByHandle(IN HANDLE hFile,
825 OUT LPDWORD dwFileAttributes,
826 IN DWORD dwFlags)
827 {
828 FILE_BASIC_INFORMATION FileBasic;
829 IO_STATUS_BLOCK IoStatusBlock;
830 NTSTATUS Status;
831
832 UNREFERENCED_PARAMETER(dwFlags);
833
834 if (IsConsoleHandle(hFile))
835 {
836 SetLastError(ERROR_INVALID_HANDLE);
837 return FALSE;
838 }
839
840 Status = NtQueryInformationFile(hFile,
841 &IoStatusBlock,
842 &FileBasic,
843 sizeof(FileBasic),
844 FileBasicInformation);
845 if (NT_SUCCESS(Status))
846 {
847 *dwFileAttributes = FileBasic.FileAttributes;
848 return TRUE;
849 }
850
851 BaseSetLastNTError(Status);
852 return FALSE;
853 }
854
855
856 /*
857 * @implemented
858 */
859 BOOL WINAPI
860 SetFileAttributesByHandle(IN HANDLE hFile,
861 IN DWORD dwFileAttributes,
862 IN DWORD dwFlags)
863 {
864 FILE_BASIC_INFORMATION FileBasic;
865 IO_STATUS_BLOCK IoStatusBlock;
866 NTSTATUS Status;
867
868 UNREFERENCED_PARAMETER(dwFlags);
869
870 if (IsConsoleHandle(hFile))
871 {
872 SetLastError(ERROR_INVALID_HANDLE);
873 return FALSE;
874 }
875
876 Status = NtQueryInformationFile(hFile,
877 &IoStatusBlock,
878 &FileBasic,
879 sizeof(FileBasic),
880 FileBasicInformation);
881 if (NT_SUCCESS(Status))
882 {
883 FileBasic.FileAttributes = dwFileAttributes;
884
885 Status = NtSetInformationFile(hFile,
886 &IoStatusBlock,
887 &FileBasic,
888 sizeof(FileBasic),
889 FileBasicInformation);
890 }
891
892 if (!NT_SUCCESS(Status))
893 {
894 BaseSetLastNTError(Status);
895 return FALSE;
896 }
897
898 return TRUE;
899 }
900
901
902 /*
903 * @implemented
904 */
905 BOOL WINAPI
906 SetFileAttributesA(
907 LPCSTR lpFileName,
908 DWORD dwFileAttributes)
909 {
910 PWCHAR FileNameW;
911
912 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
913 return FALSE;
914
915 return SetFileAttributesW(FileNameW, dwFileAttributes);
916 }
917
918
919 /*
920 * @implemented
921 */
922 BOOL
923 WINAPI
924 SetFileAttributesW(LPCWSTR lpFileName,
925 DWORD dwFileAttributes)
926 {
927 NTSTATUS Status;
928 PWSTR PathUBuffer;
929 HANDLE FileHandle;
930 UNICODE_STRING NtPathU;
931 IO_STATUS_BLOCK IoStatusBlock;
932 RTL_RELATIVE_NAME_U RelativeName;
933 OBJECT_ATTRIBUTES ObjectAttributes;
934 FILE_BASIC_INFORMATION FileInformation;
935
936 /* Get relative name */
937 if (!RtlDosPathNameToRelativeNtPathName_U(lpFileName, &NtPathU, NULL, &RelativeName))
938 {
939 SetLastError(ERROR_PATH_NOT_FOUND);
940 return FALSE;
941 }
942
943 /* Save buffer to allow later freeing */
944 PathUBuffer = NtPathU.Buffer;
945
946 /* If we have relative name (and root dir), use them instead */
947 if (RelativeName.RelativeName.Length != 0)
948 {
949 NtPathU.Length = RelativeName.RelativeName.Length;
950 NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
951 NtPathU.Buffer = RelativeName.RelativeName.Buffer;
952 }
953 else
954 {
955 RelativeName.ContainingDirectory = NULL;
956 }
957
958 /* Prepare the object attribute for opening the file */
959 InitializeObjectAttributes(&ObjectAttributes, &NtPathU,
960 OBJ_CASE_INSENSITIVE,
961 RelativeName.ContainingDirectory, NULL);
962
963 /* Attempt to open the file, while supporting reparse point */
964 Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
965 &ObjectAttributes, &IoStatusBlock,
966 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
967 FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT);
968 /* If opening failed, check whether it was because of reparse point support */
969 if (!NT_SUCCESS(Status))
970 {
971 /* Nope, just quit */
972 if (Status != STATUS_INVALID_PARAMETER)
973 {
974 RtlReleaseRelativeName(&RelativeName);
975 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
976 BaseSetLastNTError(Status);
977
978 return FALSE;
979 }
980
981 /* Yes, retry without */
982 Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
983 &ObjectAttributes, &IoStatusBlock,
984 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
985 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT);
986 if (!NT_SUCCESS(Status))
987 {
988 RtlReleaseRelativeName(&RelativeName);
989 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
990 BaseSetLastNTError(Status);
991
992 return FALSE;
993 }
994 }
995
996 /* We don't need strings anylonger */
997 RtlReleaseRelativeName(&RelativeName);
998 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
999
1000 /* Zero our structure, we'll only set file attributes */
1001 ZeroMemory(&FileInformation, sizeof(FileInformation));
1002 /* Set the attributes, filtering only allowed attributes, and forcing normal attribute */
1003 FileInformation.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL;
1004
1005 /* Finally, set the attributes */
1006 Status = NtSetInformationFile(FileHandle, &IoStatusBlock, &FileInformation,
1007 sizeof(FILE_BASIC_INFORMATION), FileBasicInformation);
1008 /* Close the file */
1009 NtClose(FileHandle);
1010
1011 /* If it failed, set the error and fail */
1012 if (!NT_SUCCESS(Status))
1013 {
1014 BaseSetLastNTError(Status);
1015
1016 return FALSE;
1017 }
1018
1019 return TRUE;
1020 }
1021
1022 /*
1023 * @implemented
1024 */
1025 BOOL WINAPI
1026 GetFileTime(IN HANDLE hFile,
1027 OUT LPFILETIME lpCreationTime OPTIONAL,
1028 OUT LPFILETIME lpLastAccessTime OPTIONAL,
1029 OUT LPFILETIME lpLastWriteTime OPTIONAL)
1030 {
1031 NTSTATUS Status;
1032 IO_STATUS_BLOCK IoStatusBlock;
1033 FILE_BASIC_INFORMATION FileBasic;
1034
1035 if(IsConsoleHandle(hFile))
1036 {
1037 BaseSetLastNTError(STATUS_INVALID_HANDLE);
1038 return FALSE;
1039 }
1040
1041 Status = NtQueryInformationFile(hFile,
1042 &IoStatusBlock,
1043 &FileBasic,
1044 sizeof(FILE_BASIC_INFORMATION),
1045 FileBasicInformation);
1046 if (!NT_SUCCESS(Status))
1047 {
1048 BaseSetLastNTError(Status);
1049 return FALSE;
1050 }
1051
1052 if (lpCreationTime)
1053 {
1054 lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart;
1055 lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart;
1056 }
1057
1058 if (lpLastAccessTime)
1059 {
1060 lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart;
1061 lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart;
1062 }
1063
1064 if (lpLastWriteTime)
1065 {
1066 lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart;
1067 lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart;
1068 }
1069
1070 return TRUE;
1071 }
1072
1073
1074 /*
1075 * @implemented
1076 */
1077 BOOL WINAPI
1078 SetFileTime(IN HANDLE hFile,
1079 CONST FILETIME *lpCreationTime OPTIONAL,
1080 CONST FILETIME *lpLastAccessTime OPTIONAL,
1081 CONST FILETIME *lpLastWriteTime OPTIONAL)
1082 {
1083 NTSTATUS Status;
1084 IO_STATUS_BLOCK IoStatusBlock;
1085 FILE_BASIC_INFORMATION FileBasic;
1086
1087 if(IsConsoleHandle(hFile))
1088 {
1089 BaseSetLastNTError(STATUS_INVALID_HANDLE);
1090 return FALSE;
1091 }
1092
1093 memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION));
1094
1095 if (lpCreationTime)
1096 {
1097 FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime;
1098 FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime;
1099 }
1100
1101 if (lpLastAccessTime)
1102 {
1103 FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime;
1104 FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime;
1105 }
1106
1107 if (lpLastWriteTime)
1108 {
1109 FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime;
1110 FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime;
1111 }
1112
1113 Status = NtSetInformationFile(hFile,
1114 &IoStatusBlock,
1115 &FileBasic,
1116 sizeof(FILE_BASIC_INFORMATION),
1117 FileBasicInformation);
1118 if (!NT_SUCCESS(Status))
1119 {
1120 BaseSetLastNTError(Status);
1121 return FALSE;
1122 }
1123
1124 return TRUE;
1125 }
1126
1127
1128 /*
1129 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1130 *
1131 * @implemented
1132 */
1133 BOOL WINAPI
1134 SetEndOfFile(HANDLE hFile)
1135 {
1136 IO_STATUS_BLOCK IoStatusBlock;
1137 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1138 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1139 FILE_POSITION_INFORMATION FilePosInfo;
1140 NTSTATUS Status;
1141
1142 if(IsConsoleHandle(hFile))
1143 {
1144 SetLastError(ERROR_INVALID_HANDLE);
1145 return FALSE;
1146 }
1147
1148 //get current position
1149 Status = NtQueryInformationFile(
1150 hFile,
1151 &IoStatusBlock,
1152 &FilePosInfo,
1153 sizeof(FILE_POSITION_INFORMATION),
1154 FilePositionInformation
1155 );
1156
1157 if (!NT_SUCCESS(Status)){
1158 BaseSetLastNTError(Status);
1159 return FALSE;
1160 }
1161
1162 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1163
1164 /*
1165 NOTE:
1166 This call is not supposed to free up any space after the eof marker
1167 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1168 But...most file systems dispatch both FileEndOfFileInformation
1169 and FileAllocationInformation as they were the same command.
1170
1171 */
1172 Status = NtSetInformationFile(
1173 hFile,
1174 &IoStatusBlock, //out
1175 &EndOfFileInfo,
1176 sizeof(FILE_END_OF_FILE_INFORMATION),
1177 FileEndOfFileInformation
1178 );
1179
1180 if (!NT_SUCCESS(Status)){
1181 BaseSetLastNTError(Status);
1182 return FALSE;
1183 }
1184
1185 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1186
1187
1188 Status = NtSetInformationFile(
1189 hFile,
1190 &IoStatusBlock, //out
1191 &FileAllocationInfo,
1192 sizeof(FILE_ALLOCATION_INFORMATION),
1193 FileAllocationInformation
1194 );
1195
1196 if (!NT_SUCCESS(Status)){
1197 BaseSetLastNTError(Status);
1198 return FALSE;
1199 }
1200
1201 return TRUE;
1202
1203 }
1204
1205
1206 /*
1207 * @implemented
1208 */
1209 BOOL
1210 WINAPI
1211 SetFileValidData(
1212 HANDLE hFile,
1213 LONGLONG ValidDataLength
1214 )
1215 {
1216 IO_STATUS_BLOCK IoStatusBlock;
1217 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1218 NTSTATUS Status;
1219
1220 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1221
1222 Status = NtSetInformationFile(
1223 hFile,
1224 &IoStatusBlock, //out
1225 &ValidDataLengthInformation,
1226 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1227 FileValidDataLengthInformation
1228 );
1229
1230 if (!NT_SUCCESS(Status)){
1231 BaseSetLastNTError(Status);
1232 return FALSE;
1233 }
1234
1235 return TRUE;
1236 }
1237
1238 /* EOF */