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