Sync with trunk r63786.
[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: lib/kernel32/file/file.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 WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
769 PWSTR FileNameW;
770 BOOL ret;
771
772 if (!lpFileName || !(FileNameW = FilenameA2W(lpFileName, FALSE)))
773 return INVALID_FILE_ATTRIBUTES;
774
775 ret = GetFileAttributesExW(FileNameW, GetFileExInfoStandard, &FileAttributeData);
776
777 return ret ? FileAttributeData.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
778 }
779
780
781 /*
782 * @implemented
783 */
784 DWORD WINAPI
785 GetFileAttributesW(LPCWSTR lpFileName)
786 {
787 WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
788 BOOL Result;
789
790 TRACE ("GetFileAttributeW(%S) called\n", lpFileName);
791
792 Result = GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &FileAttributeData);
793
794 return Result ? FileAttributeData.dwFileAttributes : INVALID_FILE_ATTRIBUTES;
795 }
796
797
798 /*
799 * @implemented
800 */
801 BOOL WINAPI
802 GetFileAttributesByHandle(IN HANDLE hFile,
803 OUT LPDWORD dwFileAttributes,
804 IN DWORD dwFlags)
805 {
806 FILE_BASIC_INFORMATION FileBasic;
807 IO_STATUS_BLOCK IoStatusBlock;
808 NTSTATUS Status;
809
810 UNREFERENCED_PARAMETER(dwFlags);
811
812 if (IsConsoleHandle(hFile))
813 {
814 SetLastError(ERROR_INVALID_HANDLE);
815 return FALSE;
816 }
817
818 Status = NtQueryInformationFile(hFile,
819 &IoStatusBlock,
820 &FileBasic,
821 sizeof(FileBasic),
822 FileBasicInformation);
823 if (NT_SUCCESS(Status))
824 {
825 *dwFileAttributes = FileBasic.FileAttributes;
826 return TRUE;
827 }
828
829 BaseSetLastNTError(Status);
830 return FALSE;
831 }
832
833
834 /*
835 * @implemented
836 */
837 BOOL WINAPI
838 SetFileAttributesByHandle(IN HANDLE hFile,
839 IN DWORD dwFileAttributes,
840 IN DWORD dwFlags)
841 {
842 FILE_BASIC_INFORMATION FileBasic;
843 IO_STATUS_BLOCK IoStatusBlock;
844 NTSTATUS Status;
845
846 UNREFERENCED_PARAMETER(dwFlags);
847
848 if (IsConsoleHandle(hFile))
849 {
850 SetLastError(ERROR_INVALID_HANDLE);
851 return FALSE;
852 }
853
854 Status = NtQueryInformationFile(hFile,
855 &IoStatusBlock,
856 &FileBasic,
857 sizeof(FileBasic),
858 FileBasicInformation);
859 if (NT_SUCCESS(Status))
860 {
861 FileBasic.FileAttributes = dwFileAttributes;
862
863 Status = NtSetInformationFile(hFile,
864 &IoStatusBlock,
865 &FileBasic,
866 sizeof(FileBasic),
867 FileBasicInformation);
868 }
869
870 if (!NT_SUCCESS(Status))
871 {
872 BaseSetLastNTError(Status);
873 return FALSE;
874 }
875
876 return TRUE;
877 }
878
879
880 /*
881 * @implemented
882 */
883 BOOL WINAPI
884 SetFileAttributesA(
885 LPCSTR lpFileName,
886 DWORD dwFileAttributes)
887 {
888 PWCHAR FileNameW;
889
890 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
891 return FALSE;
892
893 return SetFileAttributesW(FileNameW, dwFileAttributes);
894 }
895
896
897 /*
898 * @implemented
899 */
900 BOOL WINAPI
901 SetFileAttributesW(LPCWSTR lpFileName,
902 DWORD dwFileAttributes)
903 {
904 FILE_BASIC_INFORMATION FileInformation;
905 OBJECT_ATTRIBUTES ObjectAttributes;
906 IO_STATUS_BLOCK IoStatusBlock;
907 UNICODE_STRING FileName;
908 HANDLE FileHandle;
909 NTSTATUS Status;
910
911 TRACE ("SetFileAttributeW(%S, 0x%lx) called\n", lpFileName, dwFileAttributes);
912
913 /* Validate and translate the filename */
914 if (!RtlDosPathNameToNtPathName_U (lpFileName,
915 &FileName,
916 NULL,
917 NULL))
918 {
919 WARN ("Invalid path\n");
920 SetLastError (ERROR_BAD_PATHNAME);
921 return FALSE;
922 }
923 TRACE ("FileName: \'%wZ\'\n", &FileName);
924
925 /* build the object attributes */
926 InitializeObjectAttributes (&ObjectAttributes,
927 &FileName,
928 OBJ_CASE_INSENSITIVE,
929 NULL,
930 NULL);
931
932 /* Open the file */
933 Status = NtOpenFile (&FileHandle,
934 SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
935 &ObjectAttributes,
936 &IoStatusBlock,
937 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
938 FILE_SYNCHRONOUS_IO_NONALERT);
939 RtlFreeUnicodeString (&FileName);
940 if (!NT_SUCCESS (Status))
941 {
942 WARN ("NtOpenFile() failed (Status %lx)\n", Status);
943 BaseSetLastNTError (Status);
944 return FALSE;
945 }
946
947 Status = NtQueryInformationFile(FileHandle,
948 &IoStatusBlock,
949 &FileInformation,
950 sizeof(FILE_BASIC_INFORMATION),
951 FileBasicInformation);
952 if (!NT_SUCCESS(Status))
953 {
954 WARN ("SetFileAttributes NtQueryInformationFile failed with status 0x%08x\n", Status);
955 NtClose (FileHandle);
956 BaseSetLastNTError (Status);
957 return FALSE;
958 }
959
960 FileInformation.FileAttributes = dwFileAttributes;
961 Status = NtSetInformationFile(FileHandle,
962 &IoStatusBlock,
963 &FileInformation,
964 sizeof(FILE_BASIC_INFORMATION),
965 FileBasicInformation);
966 NtClose (FileHandle);
967 if (!NT_SUCCESS(Status))
968 {
969 WARN ("SetFileAttributes NtSetInformationFile failed with status 0x%08x\n", Status);
970 BaseSetLastNTError (Status);
971 return FALSE;
972 }
973
974 return TRUE;
975 }
976
977 /*
978 * @implemented
979 */
980 BOOL WINAPI
981 GetFileTime(IN HANDLE hFile,
982 OUT LPFILETIME lpCreationTime OPTIONAL,
983 OUT LPFILETIME lpLastAccessTime OPTIONAL,
984 OUT LPFILETIME lpLastWriteTime OPTIONAL)
985 {
986 NTSTATUS Status;
987 IO_STATUS_BLOCK IoStatusBlock;
988 FILE_BASIC_INFORMATION FileBasic;
989
990 if(IsConsoleHandle(hFile))
991 {
992 BaseSetLastNTError(STATUS_INVALID_HANDLE);
993 return FALSE;
994 }
995
996 Status = NtQueryInformationFile(hFile,
997 &IoStatusBlock,
998 &FileBasic,
999 sizeof(FILE_BASIC_INFORMATION),
1000 FileBasicInformation);
1001 if (!NT_SUCCESS(Status))
1002 {
1003 BaseSetLastNTError(Status);
1004 return FALSE;
1005 }
1006
1007 if (lpCreationTime)
1008 {
1009 lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart;
1010 lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart;
1011 }
1012
1013 if (lpLastAccessTime)
1014 {
1015 lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart;
1016 lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart;
1017 }
1018
1019 if (lpLastWriteTime)
1020 {
1021 lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart;
1022 lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart;
1023 }
1024
1025 return TRUE;
1026 }
1027
1028
1029 /*
1030 * @implemented
1031 */
1032 BOOL WINAPI
1033 SetFileTime(IN HANDLE hFile,
1034 CONST FILETIME *lpCreationTime OPTIONAL,
1035 CONST FILETIME *lpLastAccessTime OPTIONAL,
1036 CONST FILETIME *lpLastWriteTime OPTIONAL)
1037 {
1038 NTSTATUS Status;
1039 IO_STATUS_BLOCK IoStatusBlock;
1040 FILE_BASIC_INFORMATION FileBasic;
1041
1042 if(IsConsoleHandle(hFile))
1043 {
1044 BaseSetLastNTError(STATUS_INVALID_HANDLE);
1045 return FALSE;
1046 }
1047
1048 memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION));
1049
1050 if (lpCreationTime)
1051 {
1052 FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime;
1053 FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime;
1054 }
1055
1056 if (lpLastAccessTime)
1057 {
1058 FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime;
1059 FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime;
1060 }
1061
1062 if (lpLastWriteTime)
1063 {
1064 FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime;
1065 FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime;
1066 }
1067
1068 Status = NtSetInformationFile(hFile,
1069 &IoStatusBlock,
1070 &FileBasic,
1071 sizeof(FILE_BASIC_INFORMATION),
1072 FileBasicInformation);
1073 if (!NT_SUCCESS(Status))
1074 {
1075 BaseSetLastNTError(Status);
1076 return FALSE;
1077 }
1078
1079 return TRUE;
1080 }
1081
1082
1083 /*
1084 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1085 *
1086 * @implemented
1087 */
1088 BOOL WINAPI
1089 SetEndOfFile(HANDLE hFile)
1090 {
1091 IO_STATUS_BLOCK IoStatusBlock;
1092 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1093 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1094 FILE_POSITION_INFORMATION FilePosInfo;
1095 NTSTATUS Status;
1096
1097 if(IsConsoleHandle(hFile))
1098 {
1099 SetLastError(ERROR_INVALID_HANDLE);
1100 return FALSE;
1101 }
1102
1103 //get current position
1104 Status = NtQueryInformationFile(
1105 hFile,
1106 &IoStatusBlock,
1107 &FilePosInfo,
1108 sizeof(FILE_POSITION_INFORMATION),
1109 FilePositionInformation
1110 );
1111
1112 if (!NT_SUCCESS(Status)){
1113 BaseSetLastNTError(Status);
1114 return FALSE;
1115 }
1116
1117 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1118
1119 /*
1120 NOTE:
1121 This call is not supposed to free up any space after the eof marker
1122 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1123 But...most file systems dispatch both FileEndOfFileInformation
1124 and FileAllocationInformation as they were the same command.
1125
1126 */
1127 Status = NtSetInformationFile(
1128 hFile,
1129 &IoStatusBlock, //out
1130 &EndOfFileInfo,
1131 sizeof(FILE_END_OF_FILE_INFORMATION),
1132 FileEndOfFileInformation
1133 );
1134
1135 if (!NT_SUCCESS(Status)){
1136 BaseSetLastNTError(Status);
1137 return FALSE;
1138 }
1139
1140 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1141
1142
1143 Status = NtSetInformationFile(
1144 hFile,
1145 &IoStatusBlock, //out
1146 &FileAllocationInfo,
1147 sizeof(FILE_ALLOCATION_INFORMATION),
1148 FileAllocationInformation
1149 );
1150
1151 if (!NT_SUCCESS(Status)){
1152 BaseSetLastNTError(Status);
1153 return FALSE;
1154 }
1155
1156 return TRUE;
1157
1158 }
1159
1160
1161 /*
1162 * @implemented
1163 */
1164 BOOL
1165 WINAPI
1166 SetFileValidData(
1167 HANDLE hFile,
1168 LONGLONG ValidDataLength
1169 )
1170 {
1171 IO_STATUS_BLOCK IoStatusBlock;
1172 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1173 NTSTATUS Status;
1174
1175 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1176
1177 Status = NtSetInformationFile(
1178 hFile,
1179 &IoStatusBlock, //out
1180 &ValidDataLengthInformation,
1181 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1182 FileValidDataLengthInformation
1183 );
1184
1185 if (!NT_SUCCESS(Status)){
1186 BaseSetLastNTError(Status);
1187 return FALSE;
1188 }
1189
1190 return TRUE;
1191 }
1192
1193 /* EOF */