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 */
1259