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