2721c826315aceadb218461167a239689607cafc
[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 NTSTATUS Status;
333 IO_STATUS_BLOCK IoStatusBlock;
334 FILE_POSITION_INFORMATION FilePosition;
335 FILE_STANDARD_INFORMATION FileStandard;
336
337 if (IsConsoleHandle(hFile))
338 {
339 BaseSetLastNTError(STATUS_INVALID_HANDLE);
340 return FALSE;
341 }
342
343 switch (dwMoveMethod)
344 {
345 case FILE_CURRENT:
346 {
347 Status = NtQueryInformationFile(hFile, &IoStatusBlock,
348 &FilePosition,
349 sizeof(FILE_POSITION_INFORMATION),
350 FilePositionInformation);
351 if (!NT_SUCCESS(Status))
352 {
353 BaseSetLastNTError(Status);
354 return FALSE;
355 }
356
357 FilePosition.CurrentByteOffset.QuadPart += liDistanceToMove.QuadPart;
358 break;
359 }
360
361 case FILE_END:
362 {
363 Status = NtQueryInformationFile(hFile, &IoStatusBlock,
364 &FileStandard,
365 sizeof(FILE_STANDARD_INFORMATION),
366 FileStandardInformation);
367 if (!NT_SUCCESS(Status))
368 {
369 BaseSetLastNTError(Status);
370 return FALSE;
371 }
372
373 FilePosition.CurrentByteOffset.QuadPart = FileStandard.EndOfFile.QuadPart +
374 liDistanceToMove.QuadPart;
375 break;
376 }
377
378 case FILE_BEGIN:
379 {
380 FilePosition.CurrentByteOffset.QuadPart = liDistanceToMove.QuadPart;
381 break;
382 }
383
384 default:
385 {
386 SetLastError(ERROR_INVALID_PARAMETER);
387 return FALSE;
388 }
389 }
390
391 if (FilePosition.CurrentByteOffset.QuadPart < 0)
392 {
393 SetLastError(ERROR_NEGATIVE_SEEK);
394 return FALSE;
395 }
396
397 Status = NtSetInformationFile(hFile, &IoStatusBlock, &FilePosition,
398 sizeof(FILE_POSITION_INFORMATION),
399 FilePositionInformation);
400 if (!NT_SUCCESS(Status))
401 {
402 BaseSetLastNTError(Status);
403 return FALSE;
404 }
405
406 if (lpNewFilePointer != NULL)
407 {
408 *lpNewFilePointer = FilePosition.CurrentByteOffset;
409 }
410
411 return TRUE;
412 }
413
414
415 /*
416 * @implemented
417 */
418 DWORD WINAPI
419 GetFileType(HANDLE hFile)
420 {
421 FILE_FS_DEVICE_INFORMATION DeviceInfo;
422 IO_STATUS_BLOCK StatusBlock;
423 NTSTATUS Status;
424
425 /* Get real handle */
426 hFile = TranslateStdHandle(hFile);
427
428 /* Check for console handle */
429 if (IsConsoleHandle(hFile))
430 {
431 if (VerifyConsoleIoHandle(hFile))
432 return FILE_TYPE_CHAR;
433 }
434
435 Status = NtQueryVolumeInformationFile(hFile,
436 &StatusBlock,
437 &DeviceInfo,
438 sizeof(FILE_FS_DEVICE_INFORMATION),
439 FileFsDeviceInformation);
440 if (!NT_SUCCESS(Status))
441 {
442 BaseSetLastNTError(Status);
443 return FILE_TYPE_UNKNOWN;
444 }
445
446 switch (DeviceInfo.DeviceType)
447 {
448 case FILE_DEVICE_CD_ROM:
449 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
450 case FILE_DEVICE_CONTROLLER:
451 case FILE_DEVICE_DATALINK:
452 case FILE_DEVICE_DFS:
453 case FILE_DEVICE_DISK:
454 case FILE_DEVICE_DISK_FILE_SYSTEM:
455 case FILE_DEVICE_VIRTUAL_DISK:
456 return FILE_TYPE_DISK;
457
458 case FILE_DEVICE_KEYBOARD:
459 case FILE_DEVICE_MOUSE:
460 case FILE_DEVICE_NULL:
461 case FILE_DEVICE_PARALLEL_PORT:
462 case FILE_DEVICE_PRINTER:
463 case FILE_DEVICE_SERIAL_PORT:
464 case FILE_DEVICE_SCREEN:
465 case FILE_DEVICE_SOUND:
466 case FILE_DEVICE_MODEM:
467 return FILE_TYPE_CHAR;
468
469 case FILE_DEVICE_NAMED_PIPE:
470 return FILE_TYPE_PIPE;
471 }
472
473 return FILE_TYPE_UNKNOWN;
474 }
475
476
477 /*
478 * @implemented
479 */
480 DWORD WINAPI
481 GetFileSize(HANDLE hFile,
482 LPDWORD lpFileSizeHigh)
483 {
484 NTSTATUS errCode;
485 FILE_STANDARD_INFORMATION FileStandard;
486 IO_STATUS_BLOCK IoStatusBlock;
487
488 errCode = NtQueryInformationFile(hFile,
489 &IoStatusBlock,
490 &FileStandard,
491 sizeof(FILE_STANDARD_INFORMATION),
492 FileStandardInformation);
493 if (!NT_SUCCESS(errCode))
494 {
495 BaseSetLastNTError(errCode);
496 if ( lpFileSizeHigh == NULL )
497 {
498 return -1;
499 }
500 else
501 {
502 return 0;
503 }
504 }
505 if ( lpFileSizeHigh != NULL )
506 *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
507
508 return FileStandard.EndOfFile.u.LowPart;
509 }
510
511
512 /*
513 * @implemented
514 */
515 BOOL
516 WINAPI
517 GetFileSizeEx(
518 HANDLE hFile,
519 PLARGE_INTEGER lpFileSize
520 )
521 {
522 NTSTATUS errCode;
523 FILE_STANDARD_INFORMATION FileStandard;
524 IO_STATUS_BLOCK IoStatusBlock;
525
526 errCode = NtQueryInformationFile(hFile,
527 &IoStatusBlock,
528 &FileStandard,
529 sizeof(FILE_STANDARD_INFORMATION),
530 FileStandardInformation);
531 if (!NT_SUCCESS(errCode))
532 {
533 BaseSetLastNTError(errCode);
534 return FALSE;
535 }
536 if (lpFileSize)
537 *lpFileSize = FileStandard.EndOfFile;
538
539 return TRUE;
540 }
541
542
543 /*
544 * @implemented
545 */
546 DWORD WINAPI
547 GetCompressedFileSizeA(LPCSTR lpFileName,
548 LPDWORD lpFileSizeHigh)
549 {
550 PWCHAR FileNameW;
551
552 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
553 return INVALID_FILE_SIZE;
554
555 return GetCompressedFileSizeW(FileNameW, lpFileSizeHigh);
556 }
557
558
559 /*
560 * @implemented
561 */
562 DWORD WINAPI
563 GetCompressedFileSizeW(LPCWSTR lpFileName,
564 LPDWORD lpFileSizeHigh)
565 {
566 FILE_COMPRESSION_INFORMATION FileCompression;
567 NTSTATUS errCode;
568 IO_STATUS_BLOCK IoStatusBlock;
569 HANDLE hFile;
570
571 hFile = CreateFileW(lpFileName,
572 GENERIC_READ,
573 FILE_SHARE_READ,
574 NULL,
575 OPEN_EXISTING,
576 FILE_ATTRIBUTE_NORMAL,
577 NULL);
578
579 if (hFile == INVALID_HANDLE_VALUE)
580 return INVALID_FILE_SIZE;
581
582 errCode = NtQueryInformationFile(hFile,
583 &IoStatusBlock,
584 &FileCompression,
585 sizeof(FILE_COMPRESSION_INFORMATION),
586 FileCompressionInformation);
587
588 CloseHandle(hFile);
589
590 if (!NT_SUCCESS(errCode))
591 {
592 BaseSetLastNTError(errCode);
593 return INVALID_FILE_SIZE;
594 }
595
596 if(lpFileSizeHigh)
597 *lpFileSizeHigh = FileCompression.CompressedFileSize.u.HighPart;
598
599 SetLastError(NO_ERROR);
600 return FileCompression.CompressedFileSize.u.LowPart;
601 }
602
603
604 /*
605 * @implemented
606 */
607 BOOL WINAPI
608 GetFileInformationByHandle(HANDLE hFile,
609 LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
610 {
611 struct
612 {
613 FILE_FS_VOLUME_INFORMATION FileFsVolume;
614 WCHAR Name[255];
615 }
616 FileFsVolume;
617
618 FILE_BASIC_INFORMATION FileBasic;
619 FILE_INTERNAL_INFORMATION FileInternal;
620 FILE_STANDARD_INFORMATION FileStandard;
621 NTSTATUS errCode;
622 IO_STATUS_BLOCK IoStatusBlock;
623
624 if(IsConsoleHandle(hFile))
625 {
626 SetLastError(ERROR_INVALID_HANDLE);
627 return FALSE;
628 }
629
630 errCode = NtQueryInformationFile(hFile,
631 &IoStatusBlock,
632 &FileBasic,
633 sizeof(FILE_BASIC_INFORMATION),
634 FileBasicInformation);
635 if (!NT_SUCCESS(errCode))
636 {
637 BaseSetLastNTError(errCode);
638 return FALSE;
639 }
640
641 lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes;
642
643 lpFileInformation->ftCreationTime.dwHighDateTime = FileBasic.CreationTime.u.HighPart;
644 lpFileInformation->ftCreationTime.dwLowDateTime = FileBasic.CreationTime.u.LowPart;
645
646 lpFileInformation->ftLastAccessTime.dwHighDateTime = FileBasic.LastAccessTime.u.HighPart;
647 lpFileInformation->ftLastAccessTime.dwLowDateTime = FileBasic.LastAccessTime.u.LowPart;
648
649 lpFileInformation->ftLastWriteTime.dwHighDateTime = FileBasic.LastWriteTime.u.HighPart;
650 lpFileInformation->ftLastWriteTime.dwLowDateTime = FileBasic.LastWriteTime.u.LowPart;
651
652 errCode = NtQueryInformationFile(hFile,
653 &IoStatusBlock,
654 &FileInternal,
655 sizeof(FILE_INTERNAL_INFORMATION),
656 FileInternalInformation);
657 if (!NT_SUCCESS(errCode))
658 {
659 BaseSetLastNTError(errCode);
660 return FALSE;
661 }
662
663 lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart;
664 lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart;
665
666 errCode = NtQueryVolumeInformationFile(hFile,
667 &IoStatusBlock,
668 &FileFsVolume,
669 sizeof(FileFsVolume),
670 FileFsVolumeInformation);
671 if (!NT_SUCCESS(errCode))
672 {
673 BaseSetLastNTError(errCode);
674 return FALSE;
675 }
676
677 lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber;
678
679 errCode = NtQueryInformationFile(hFile,
680 &IoStatusBlock,
681 &FileStandard,
682 sizeof(FILE_STANDARD_INFORMATION),
683 FileStandardInformation);
684 if (!NT_SUCCESS(errCode))
685 {
686 BaseSetLastNTError(errCode);
687 return FALSE;
688 }
689
690 lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks;
691 lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
692 lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart;
693
694 return TRUE;
695 }
696
697
698 /*
699 * @implemented
700 */
701 BOOL WINAPI
702 GetFileAttributesExW(LPCWSTR lpFileName,
703 GET_FILEEX_INFO_LEVELS fInfoLevelId,
704 LPVOID lpFileInformation)
705 {
706 FILE_NETWORK_OPEN_INFORMATION FileInformation;
707 OBJECT_ATTRIBUTES ObjectAttributes;
708 UNICODE_STRING FileName;
709 NTSTATUS Status;
710 WIN32_FILE_ATTRIBUTE_DATA* FileAttributeData;
711
712 TRACE("GetFileAttributesExW(%S) called\n", lpFileName);
713
714
715 if (fInfoLevelId != GetFileExInfoStandard || lpFileInformation == NULL)
716 {
717 SetLastError(ERROR_INVALID_PARAMETER);
718 return FALSE;
719 }
720
721 /* Validate and translate the filename */
722 if (!RtlDosPathNameToNtPathName_U (lpFileName,
723 &FileName,
724 NULL,
725 NULL))
726 {
727 WARN ("Invalid path '%S'\n", lpFileName);
728 SetLastError (ERROR_BAD_PATHNAME);
729 return FALSE;
730 }
731
732 /* build the object attributes */
733 InitializeObjectAttributes (&ObjectAttributes,
734 &FileName,
735 OBJ_CASE_INSENSITIVE,
736 NULL,
737 NULL);
738
739 /* Get file attributes */
740 Status = NtQueryFullAttributesFile(&ObjectAttributes,
741 &FileInformation);
742
743 RtlFreeUnicodeString (&FileName);
744 if (!NT_SUCCESS (Status))
745 {
746 WARN ("NtQueryFullAttributesFile() failed (Status %lx)\n", Status);
747 BaseSetLastNTError (Status);
748 return FALSE;
749 }
750
751 FileAttributeData = (WIN32_FILE_ATTRIBUTE_DATA*)lpFileInformation;
752 FileAttributeData->dwFileAttributes = FileInformation.FileAttributes;
753 FileAttributeData->ftCreationTime.dwLowDateTime = FileInformation.CreationTime.u.LowPart;
754 FileAttributeData->ftCreationTime.dwHighDateTime = FileInformation.CreationTime.u.HighPart;
755 FileAttributeData->ftLastAccessTime.dwLowDateTime = FileInformation.LastAccessTime.u.LowPart;
756 FileAttributeData->ftLastAccessTime.dwHighDateTime = FileInformation.LastAccessTime.u.HighPart;
757 FileAttributeData->ftLastWriteTime.dwLowDateTime = FileInformation.LastWriteTime.u.LowPart;
758 FileAttributeData->ftLastWriteTime.dwHighDateTime = FileInformation.LastWriteTime.u.HighPart;
759 FileAttributeData->nFileSizeLow = FileInformation.EndOfFile.u.LowPart;
760 FileAttributeData->nFileSizeHigh = FileInformation.EndOfFile.u.HighPart;
761
762 return TRUE;
763 }
764
765 /*
766 * @implemented
767 */
768 BOOL WINAPI
769 GetFileAttributesExA(LPCSTR lpFileName,
770 GET_FILEEX_INFO_LEVELS fInfoLevelId,
771 LPVOID lpFileInformation)
772 {
773 PWCHAR FileNameW;
774
775 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
776 return FALSE;
777
778 return GetFileAttributesExW(FileNameW, fInfoLevelId, lpFileInformation);
779 }
780
781
782 /*
783 * @implemented
784 */
785 DWORD WINAPI
786 GetFileAttributesA(LPCSTR lpFileName)
787 {
788 PWSTR FileNameW;
789
790 if (!lpFileName || !(FileNameW = FilenameA2W(lpFileName, FALSE)))
791 return INVALID_FILE_ATTRIBUTES;
792
793 return GetFileAttributesW(FileNameW);
794 }
795
796
797 /*
798 * @implemented
799 */
800 DWORD
801 WINAPI
802 GetFileAttributesW(LPCWSTR lpFileName)
803 {
804 NTSTATUS Status;
805 UNICODE_STRING FileName;
806 OBJECT_ATTRIBUTES ObjectAttributes;
807 FILE_BASIC_INFORMATION FileInformation;
808
809 /* Get the NT path name */
810 if (!RtlDosPathNameToNtPathName_U(lpFileName, &FileName, NULL, NULL))
811 {
812 SetLastError(ERROR_PATH_NOT_FOUND);
813 return INVALID_FILE_ATTRIBUTES;
814 }
815
816 /* Prepare for querying attributes */
817 InitializeObjectAttributes(&ObjectAttributes, &FileName,
818 OBJ_CASE_INSENSITIVE,
819 NULL, NULL);
820 /* Simply query attributes */
821 Status = NtQueryAttributesFile(&ObjectAttributes, &FileInformation);
822 if (!NT_SUCCESS(Status))
823 {
824 /* It failed? Is it a DOS device? */
825 if (RtlIsDosDeviceName_U(lpFileName))
826 {
827 return FILE_ATTRIBUTE_ARCHIVE;
828 }
829
830 /* Set the error otherwise */
831 BaseSetLastNTError(Status);
832 return INVALID_FILE_ATTRIBUTES;
833 }
834
835 /* Return the file attributes */
836 return FileInformation.FileAttributes;
837 }
838
839
840 /*
841 * @implemented
842 */
843 BOOL WINAPI
844 GetFileAttributesByHandle(IN HANDLE hFile,
845 OUT LPDWORD dwFileAttributes,
846 IN DWORD dwFlags)
847 {
848 FILE_BASIC_INFORMATION FileBasic;
849 IO_STATUS_BLOCK IoStatusBlock;
850 NTSTATUS Status;
851
852 UNREFERENCED_PARAMETER(dwFlags);
853
854 if (IsConsoleHandle(hFile))
855 {
856 SetLastError(ERROR_INVALID_HANDLE);
857 return FALSE;
858 }
859
860 Status = NtQueryInformationFile(hFile,
861 &IoStatusBlock,
862 &FileBasic,
863 sizeof(FileBasic),
864 FileBasicInformation);
865 if (NT_SUCCESS(Status))
866 {
867 *dwFileAttributes = FileBasic.FileAttributes;
868 return TRUE;
869 }
870
871 BaseSetLastNTError(Status);
872 return FALSE;
873 }
874
875
876 /*
877 * @implemented
878 */
879 BOOL WINAPI
880 SetFileAttributesByHandle(IN HANDLE hFile,
881 IN DWORD dwFileAttributes,
882 IN DWORD dwFlags)
883 {
884 FILE_BASIC_INFORMATION FileBasic;
885 IO_STATUS_BLOCK IoStatusBlock;
886 NTSTATUS Status;
887
888 UNREFERENCED_PARAMETER(dwFlags);
889
890 if (IsConsoleHandle(hFile))
891 {
892 SetLastError(ERROR_INVALID_HANDLE);
893 return FALSE;
894 }
895
896 Status = NtQueryInformationFile(hFile,
897 &IoStatusBlock,
898 &FileBasic,
899 sizeof(FileBasic),
900 FileBasicInformation);
901 if (NT_SUCCESS(Status))
902 {
903 FileBasic.FileAttributes = dwFileAttributes;
904
905 Status = NtSetInformationFile(hFile,
906 &IoStatusBlock,
907 &FileBasic,
908 sizeof(FileBasic),
909 FileBasicInformation);
910 }
911
912 if (!NT_SUCCESS(Status))
913 {
914 BaseSetLastNTError(Status);
915 return FALSE;
916 }
917
918 return TRUE;
919 }
920
921
922 /*
923 * @implemented
924 */
925 BOOL WINAPI
926 SetFileAttributesA(
927 LPCSTR lpFileName,
928 DWORD dwFileAttributes)
929 {
930 PWCHAR FileNameW;
931
932 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
933 return FALSE;
934
935 return SetFileAttributesW(FileNameW, dwFileAttributes);
936 }
937
938
939 /*
940 * @implemented
941 */
942 BOOL
943 WINAPI
944 SetFileAttributesW(LPCWSTR lpFileName,
945 DWORD dwFileAttributes)
946 {
947 NTSTATUS Status;
948 PWSTR PathUBuffer;
949 HANDLE FileHandle;
950 UNICODE_STRING NtPathU;
951 IO_STATUS_BLOCK IoStatusBlock;
952 RTL_RELATIVE_NAME_U RelativeName;
953 OBJECT_ATTRIBUTES ObjectAttributes;
954 FILE_BASIC_INFORMATION FileInformation;
955
956 /* Get relative name */
957 if (!RtlDosPathNameToRelativeNtPathName_U(lpFileName, &NtPathU, NULL, &RelativeName))
958 {
959 SetLastError(ERROR_PATH_NOT_FOUND);
960 return FALSE;
961 }
962
963 /* Save buffer to allow later freeing */
964 PathUBuffer = NtPathU.Buffer;
965
966 /* If we have relative name (and root dir), use them instead */
967 if (RelativeName.RelativeName.Length != 0)
968 {
969 NtPathU.Length = RelativeName.RelativeName.Length;
970 NtPathU.MaximumLength = RelativeName.RelativeName.MaximumLength;
971 NtPathU.Buffer = RelativeName.RelativeName.Buffer;
972 }
973 else
974 {
975 RelativeName.ContainingDirectory = NULL;
976 }
977
978 /* Prepare the object attribute for opening the file */
979 InitializeObjectAttributes(&ObjectAttributes, &NtPathU,
980 OBJ_CASE_INSENSITIVE,
981 RelativeName.ContainingDirectory, NULL);
982
983 /* Attempt to open the file, while supporting reparse point */
984 Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
985 &ObjectAttributes, &IoStatusBlock,
986 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
987 FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT);
988 /* If opening failed, check whether it was because of reparse point support */
989 if (!NT_SUCCESS(Status))
990 {
991 /* Nope, just quit */
992 if (Status != STATUS_INVALID_PARAMETER)
993 {
994 RtlReleaseRelativeName(&RelativeName);
995 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
996 BaseSetLastNTError(Status);
997
998 return FALSE;
999 }
1000
1001 /* Yes, retry without */
1002 Status = NtOpenFile(&FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
1003 &ObjectAttributes, &IoStatusBlock,
1004 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1005 FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT);
1006 if (!NT_SUCCESS(Status))
1007 {
1008 RtlReleaseRelativeName(&RelativeName);
1009 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
1010 BaseSetLastNTError(Status);
1011
1012 return FALSE;
1013 }
1014 }
1015
1016 /* We don't need strings anylonger */
1017 RtlReleaseRelativeName(&RelativeName);
1018 RtlFreeHeap(RtlGetProcessHeap(), 0, PathUBuffer);
1019
1020 /* Zero our structure, we'll only set file attributes */
1021 ZeroMemory(&FileInformation, sizeof(FileInformation));
1022 /* Set the attributes, filtering only allowed attributes, and forcing normal attribute */
1023 FileInformation.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_SET_FLAGS) | FILE_ATTRIBUTE_NORMAL;
1024
1025 /* Finally, set the attributes */
1026 Status = NtSetInformationFile(FileHandle, &IoStatusBlock, &FileInformation,
1027 sizeof(FILE_BASIC_INFORMATION), FileBasicInformation);
1028 /* Close the file */
1029 NtClose(FileHandle);
1030
1031 /* If it failed, set the error and fail */
1032 if (!NT_SUCCESS(Status))
1033 {
1034 BaseSetLastNTError(Status);
1035
1036 return FALSE;
1037 }
1038
1039 return TRUE;
1040 }
1041
1042 /*
1043 * @implemented
1044 */
1045 BOOL WINAPI
1046 GetFileTime(IN HANDLE hFile,
1047 OUT LPFILETIME lpCreationTime OPTIONAL,
1048 OUT LPFILETIME lpLastAccessTime OPTIONAL,
1049 OUT LPFILETIME lpLastWriteTime OPTIONAL)
1050 {
1051 NTSTATUS Status;
1052 IO_STATUS_BLOCK IoStatusBlock;
1053 FILE_BASIC_INFORMATION FileBasic;
1054
1055 if(IsConsoleHandle(hFile))
1056 {
1057 BaseSetLastNTError(STATUS_INVALID_HANDLE);
1058 return FALSE;
1059 }
1060
1061 Status = NtQueryInformationFile(hFile,
1062 &IoStatusBlock,
1063 &FileBasic,
1064 sizeof(FILE_BASIC_INFORMATION),
1065 FileBasicInformation);
1066 if (!NT_SUCCESS(Status))
1067 {
1068 BaseSetLastNTError(Status);
1069 return FALSE;
1070 }
1071
1072 if (lpCreationTime)
1073 {
1074 lpCreationTime->dwLowDateTime = FileBasic.CreationTime.LowPart;
1075 lpCreationTime->dwHighDateTime = FileBasic.CreationTime.HighPart;
1076 }
1077
1078 if (lpLastAccessTime)
1079 {
1080 lpLastAccessTime->dwLowDateTime = FileBasic.LastAccessTime.LowPart;
1081 lpLastAccessTime->dwHighDateTime = FileBasic.LastAccessTime.HighPart;
1082 }
1083
1084 if (lpLastWriteTime)
1085 {
1086 lpLastWriteTime->dwLowDateTime = FileBasic.LastWriteTime.LowPart;
1087 lpLastWriteTime->dwHighDateTime = FileBasic.LastWriteTime.HighPart;
1088 }
1089
1090 return TRUE;
1091 }
1092
1093
1094 /*
1095 * @implemented
1096 */
1097 BOOL WINAPI
1098 SetFileTime(IN HANDLE hFile,
1099 CONST FILETIME *lpCreationTime OPTIONAL,
1100 CONST FILETIME *lpLastAccessTime OPTIONAL,
1101 CONST FILETIME *lpLastWriteTime OPTIONAL)
1102 {
1103 NTSTATUS Status;
1104 IO_STATUS_BLOCK IoStatusBlock;
1105 FILE_BASIC_INFORMATION FileBasic;
1106
1107 if(IsConsoleHandle(hFile))
1108 {
1109 BaseSetLastNTError(STATUS_INVALID_HANDLE);
1110 return FALSE;
1111 }
1112
1113 memset(&FileBasic, 0, sizeof(FILE_BASIC_INFORMATION));
1114
1115 if (lpCreationTime)
1116 {
1117 FileBasic.CreationTime.LowPart = lpCreationTime->dwLowDateTime;
1118 FileBasic.CreationTime.HighPart = lpCreationTime->dwHighDateTime;
1119 }
1120
1121 if (lpLastAccessTime)
1122 {
1123 FileBasic.LastAccessTime.LowPart = lpLastAccessTime->dwLowDateTime;
1124 FileBasic.LastAccessTime.HighPart = lpLastAccessTime->dwHighDateTime;
1125 }
1126
1127 if (lpLastWriteTime)
1128 {
1129 FileBasic.LastWriteTime.LowPart = lpLastWriteTime->dwLowDateTime;
1130 FileBasic.LastWriteTime.HighPart = lpLastWriteTime->dwHighDateTime;
1131 }
1132
1133 Status = NtSetInformationFile(hFile,
1134 &IoStatusBlock,
1135 &FileBasic,
1136 sizeof(FILE_BASIC_INFORMATION),
1137 FileBasicInformation);
1138 if (!NT_SUCCESS(Status))
1139 {
1140 BaseSetLastNTError(Status);
1141 return FALSE;
1142 }
1143
1144 return TRUE;
1145 }
1146
1147
1148 /*
1149 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1150 *
1151 * @implemented
1152 */
1153 BOOL WINAPI
1154 SetEndOfFile(HANDLE hFile)
1155 {
1156 IO_STATUS_BLOCK IoStatusBlock;
1157 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1158 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1159 FILE_POSITION_INFORMATION FilePosInfo;
1160 NTSTATUS Status;
1161
1162 if(IsConsoleHandle(hFile))
1163 {
1164 SetLastError(ERROR_INVALID_HANDLE);
1165 return FALSE;
1166 }
1167
1168 //get current position
1169 Status = NtQueryInformationFile(
1170 hFile,
1171 &IoStatusBlock,
1172 &FilePosInfo,
1173 sizeof(FILE_POSITION_INFORMATION),
1174 FilePositionInformation
1175 );
1176
1177 if (!NT_SUCCESS(Status)){
1178 BaseSetLastNTError(Status);
1179 return FALSE;
1180 }
1181
1182 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1183
1184 /*
1185 NOTE:
1186 This call is not supposed to free up any space after the eof marker
1187 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1188 But...most file systems dispatch both FileEndOfFileInformation
1189 and FileAllocationInformation as they were the same command.
1190
1191 */
1192 Status = NtSetInformationFile(
1193 hFile,
1194 &IoStatusBlock, //out
1195 &EndOfFileInfo,
1196 sizeof(FILE_END_OF_FILE_INFORMATION),
1197 FileEndOfFileInformation
1198 );
1199
1200 if (!NT_SUCCESS(Status)){
1201 BaseSetLastNTError(Status);
1202 return FALSE;
1203 }
1204
1205 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1206
1207
1208 Status = NtSetInformationFile(
1209 hFile,
1210 &IoStatusBlock, //out
1211 &FileAllocationInfo,
1212 sizeof(FILE_ALLOCATION_INFORMATION),
1213 FileAllocationInformation
1214 );
1215
1216 if (!NT_SUCCESS(Status)){
1217 BaseSetLastNTError(Status);
1218 return FALSE;
1219 }
1220
1221 return TRUE;
1222
1223 }
1224
1225
1226 /*
1227 * @implemented
1228 */
1229 BOOL
1230 WINAPI
1231 SetFileValidData(
1232 HANDLE hFile,
1233 LONGLONG ValidDataLength
1234 )
1235 {
1236 IO_STATUS_BLOCK IoStatusBlock;
1237 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1238 NTSTATUS Status;
1239
1240 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1241
1242 Status = NtSetInformationFile(
1243 hFile,
1244 &IoStatusBlock, //out
1245 &ValidDataLengthInformation,
1246 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1247 FileValidDataLengthInformation
1248 );
1249
1250 if (!NT_SUCCESS(Status)){
1251 BaseSetLastNTError(Status);
1252 return FALSE;
1253 }
1254
1255 return TRUE;
1256 }
1257
1258 /* EOF */