Manually applying Gunnars patch because it's easier this way - and a good chance...
[reactos.git] / reactos / lib / kernel32 / file / file.c
1 /* $Id: file.c,v 1.38 2002/11/07 02:52:37 robd Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/file.c
6 * PURPOSE: Directory functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * GetTempFileName is modified from WINE [ Alexandre Juiliard ]
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ddk/ntddk.h>
16 #include <windows.h>
17 #include <wchar.h>
18 #include <string.h>
19
20 #define NDEBUG
21 #include <kernel32/kernel32.h>
22 #include <kernel32/error.h>
23
24 #define LPPROGRESS_ROUTINE void*
25
26
27 /* GLOBALS ******************************************************************/
28
29 WINBOOL bIsFileApiAnsi = TRUE; // set the file api to ansi or oem
30
31
32 /* FUNCTIONS ****************************************************************/
33
34 VOID STDCALL
35 SetFileApisToOEM(VOID)
36 {
37 bIsFileApiAnsi = FALSE;
38 }
39
40
41 VOID STDCALL
42 SetFileApisToANSI(VOID)
43 {
44 bIsFileApiAnsi = TRUE;
45 }
46
47
48 WINBOOL STDCALL
49 AreFileApisANSI(VOID)
50 {
51 return bIsFileApiAnsi;
52 }
53
54
55 HFILE STDCALL
56 OpenFile(LPCSTR lpFileName,
57 LPOFSTRUCT lpReOpenBuff,
58 UINT uStyle)
59 {
60 OBJECT_ATTRIBUTES ObjectAttributes;
61 IO_STATUS_BLOCK IoStatusBlock;
62 UNICODE_STRING FileNameString;
63 UNICODE_STRING FileNameU;
64 ANSI_STRING FileName;
65 WCHAR PathNameW[MAX_PATH];
66 HANDLE FileHandle = NULL;
67 NTSTATUS errCode;
68 PWCHAR FilePart;
69 ULONG Len;
70
71 DPRINT("OpenFile('%s', lpReOpenBuff %x, uStyle %x)\n", lpFileName, lpReOpenBuff, uStyle);
72
73 if (lpReOpenBuff == NULL)
74 {
75 return FALSE;
76 }
77
78 RtlInitAnsiString (&FileName, (LPSTR)lpFileName);
79
80 /* convert ansi (or oem) string to unicode */
81 if (bIsFileApiAnsi)
82 RtlAnsiStringToUnicodeString (&FileNameU, &FileName, TRUE);
83 else
84 RtlOemStringToUnicodeString (&FileNameU, &FileName, TRUE);
85
86 Len = SearchPathW (NULL,
87 FileNameU.Buffer,
88 NULL,
89 OFS_MAXPATHNAME,
90 PathNameW,
91 &FilePart);
92
93 RtlFreeUnicodeString(&FileNameU);
94
95 if (Len == 0 || Len > OFS_MAXPATHNAME)
96 {
97 return (HFILE)INVALID_HANDLE_VALUE;
98 }
99
100 FileName.Buffer = lpReOpenBuff->szPathName;
101 FileName.Length = 0;
102 FileName.MaximumLength = OFS_MAXPATHNAME;
103
104 RtlInitUnicodeString(&FileNameU, PathNameW);
105
106 /* convert unicode string to ansi (or oem) */
107 if (bIsFileApiAnsi)
108 RtlUnicodeStringToAnsiString (&FileName, &FileNameU, FALSE);
109 else
110 RtlUnicodeStringToOemString (&FileName, &FileNameU, FALSE);
111
112 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)PathNameW,
113 &FileNameString,
114 NULL,
115 NULL))
116 {
117 return (HFILE)INVALID_HANDLE_VALUE;
118 }
119
120 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
121 ObjectAttributes.RootDirectory = NULL;
122 ObjectAttributes.ObjectName = &FileNameString;
123 ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT;
124 ObjectAttributes.SecurityDescriptor = NULL;
125 ObjectAttributes.SecurityQualityOfService = NULL;
126
127 // FILE_SHARE_READ
128 // FILE_NO_INTERMEDIATE_BUFFERING
129
130 if ((uStyle & OF_PARSE) == OF_PARSE)
131 {
132 RtlFreeUnicodeString(&FileNameString);
133 return (HFILE)NULL;
134 }
135
136 errCode = NtOpenFile (&FileHandle,
137 GENERIC_READ|SYNCHRONIZE,
138 &ObjectAttributes,
139 &IoStatusBlock,
140 FILE_SHARE_READ,
141 FILE_NON_DIRECTORY_FILE);
142
143 RtlFreeUnicodeString(&FileNameString);
144
145 lpReOpenBuff->nErrCode = RtlNtStatusToDosError(errCode);
146
147 if (!NT_SUCCESS(errCode))
148 {
149 SetLastErrorByStatus (errCode);
150 return (HFILE)INVALID_HANDLE_VALUE;
151 }
152
153 return (HFILE)FileHandle;
154 }
155
156
157 WINBOOL STDCALL
158 FlushFileBuffers(HANDLE hFile)
159 {
160 NTSTATUS errCode;
161 IO_STATUS_BLOCK IoStatusBlock;
162
163 if (IsConsoleHandle(hFile))
164 {
165 return FALSE;
166 }
167
168 errCode = NtFlushBuffersFile(hFile,
169 &IoStatusBlock);
170 if (!NT_SUCCESS(errCode))
171 {
172 SetLastErrorByStatus(errCode);
173 return(FALSE);
174 }
175 return(TRUE);
176 }
177
178
179 DWORD STDCALL
180 SetFilePointer(HANDLE hFile,
181 LONG lDistanceToMove,
182 PLONG lpDistanceToMoveHigh,
183 DWORD dwMoveMethod)
184 {
185 FILE_POSITION_INFORMATION FilePosition;
186 FILE_STANDARD_INFORMATION FileStandart;
187 NTSTATUS errCode;
188 IO_STATUS_BLOCK IoStatusBlock;
189 LARGE_INTEGER Distance;
190
191 DPRINT("SetFilePointer(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n",
192 hFile,lDistanceToMove,dwMoveMethod);
193
194 Distance.u.LowPart = lDistanceToMove;
195 if (lpDistanceToMoveHigh)
196 {
197 Distance.u.HighPart = *lpDistanceToMoveHigh;
198 }
199 else if (lDistanceToMove >= 0)
200 {
201 Distance.u.HighPart = 0;
202 }
203 else
204 {
205 Distance.u.HighPart = -1;
206 }
207
208 if (dwMoveMethod == FILE_CURRENT)
209 {
210 NtQueryInformationFile(hFile,
211 &IoStatusBlock,
212 &FilePosition,
213 sizeof(FILE_POSITION_INFORMATION),
214 FilePositionInformation);
215 FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
216 }
217 else if (dwMoveMethod == FILE_END)
218 {
219 NtQueryInformationFile(hFile,
220 &IoStatusBlock,
221 &FileStandart,
222 sizeof(FILE_STANDARD_INFORMATION),
223 FileStandardInformation);
224 FilePosition.CurrentByteOffset.QuadPart =
225 FileStandart.EndOfFile.QuadPart + Distance.QuadPart;
226 }
227 else if ( dwMoveMethod == FILE_BEGIN )
228 {
229 FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
230 }
231
232 errCode = NtSetInformationFile(hFile,
233 &IoStatusBlock,
234 &FilePosition,
235 sizeof(FILE_POSITION_INFORMATION),
236 FilePositionInformation);
237 if (!NT_SUCCESS(errCode))
238 {
239 SetLastErrorByStatus(errCode);
240 return -1;
241 }
242
243 if (lpDistanceToMoveHigh != NULL)
244 {
245 *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
246 }
247 return FilePosition.CurrentByteOffset.u.LowPart;
248 }
249
250
251 DWORD STDCALL
252 GetFileType(HANDLE hFile)
253 {
254 FILE_FS_DEVICE_INFORMATION DeviceInfo;
255 IO_STATUS_BLOCK StatusBlock;
256 NTSTATUS Status;
257
258 /* get real handle */
259 switch ((ULONG)hFile)
260 {
261 case STD_INPUT_HANDLE:
262 hFile = NtCurrentPeb()->ProcessParameters->hStdInput;
263
264 break;
265
266 case STD_OUTPUT_HANDLE:
267 hFile = NtCurrentPeb()->ProcessParameters->hStdOutput;
268
269 break;
270
271 case STD_ERROR_HANDLE:
272 hFile = NtCurrentPeb()->ProcessParameters->hStdError;
273
274 break;
275 }
276
277 /* check console handles */
278 if (IsConsoleHandle(hFile))
279 {
280 // if (VerifyConsoleHandle(hFile))
281 return FILE_TYPE_CHAR;
282 }
283
284 Status = NtQueryVolumeInformationFile(hFile,
285 &StatusBlock,
286 &DeviceInfo,
287 sizeof(FILE_FS_DEVICE_INFORMATION),
288 FileFsDeviceInformation);
289 if (!NT_SUCCESS(Status))
290 {
291 SetLastErrorByStatus(Status);
292 return FILE_TYPE_UNKNOWN;
293 }
294
295 switch (DeviceInfo.DeviceType)
296 {
297 case FILE_DEVICE_CD_ROM:
298 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
299 case FILE_DEVICE_CONTROLLER:
300 case FILE_DEVICE_DATALINK:
301 case FILE_DEVICE_DFS:
302 case FILE_DEVICE_DISK:
303 case FILE_DEVICE_DISK_FILE_SYSTEM:
304 case FILE_DEVICE_VIRTUAL_DISK:
305 return FILE_TYPE_DISK;
306
307 case FILE_DEVICE_KEYBOARD:
308 case FILE_DEVICE_MOUSE:
309 case FILE_DEVICE_NULL:
310 case FILE_DEVICE_PARALLEL_PORT:
311 case FILE_DEVICE_PRINTER:
312 case FILE_DEVICE_SERIAL_PORT:
313 case FILE_DEVICE_SCREEN:
314 case FILE_DEVICE_SOUND:
315 case FILE_DEVICE_MODEM:
316 return FILE_TYPE_CHAR;
317
318 case FILE_DEVICE_NAMED_PIPE:
319 return FILE_TYPE_PIPE;
320 }
321
322 return FILE_TYPE_UNKNOWN;
323 }
324
325
326 DWORD STDCALL
327 GetFileSize(HANDLE hFile,
328 LPDWORD lpFileSizeHigh)
329 {
330 NTSTATUS errCode;
331 FILE_STANDARD_INFORMATION FileStandard;
332 IO_STATUS_BLOCK IoStatusBlock;
333
334 errCode = NtQueryInformationFile(hFile,
335 &IoStatusBlock,
336 &FileStandard,
337 sizeof(FILE_STANDARD_INFORMATION),
338 FileStandardInformation);
339 if (!NT_SUCCESS(errCode))
340 {
341 SetLastErrorByStatus(errCode);
342 if ( lpFileSizeHigh == NULL )
343 {
344 return -1;
345 }
346 else
347 {
348 return 0;
349 }
350 }
351 if ( lpFileSizeHigh != NULL )
352 *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
353
354 return FileStandard.EndOfFile.u.LowPart;
355 }
356
357
358 DWORD STDCALL
359 GetCompressedFileSizeA(LPCSTR lpFileName,
360 LPDWORD lpFileSizeHigh)
361 {
362 UNICODE_STRING FileNameU;
363 ANSI_STRING FileName;
364 DWORD Size;
365
366 RtlInitAnsiString(&FileName,
367 (LPSTR)lpFileName);
368
369 /* convert ansi (or oem) string to unicode */
370 if (bIsFileApiAnsi)
371 RtlAnsiStringToUnicodeString(&FileNameU,
372 &FileName,
373 TRUE);
374 else
375 RtlOemStringToUnicodeString(&FileNameU,
376 &FileName,
377 TRUE);
378
379 Size = GetCompressedFileSizeW(FileNameU.Buffer,
380 lpFileSizeHigh);
381
382 RtlFreeUnicodeString (&FileNameU);
383
384 return Size;
385 }
386
387
388 DWORD STDCALL
389 GetCompressedFileSizeW(LPCWSTR lpFileName,
390 LPDWORD lpFileSizeHigh)
391 {
392 FILE_COMPRESSION_INFORMATION FileCompression;
393 NTSTATUS errCode;
394 IO_STATUS_BLOCK IoStatusBlock;
395 HANDLE hFile;
396
397 hFile = CreateFileW(lpFileName,
398 GENERIC_READ,
399 FILE_SHARE_READ,
400 NULL,
401 OPEN_EXISTING,
402 FILE_ATTRIBUTE_NORMAL,
403 NULL);
404
405 errCode = NtQueryInformationFile(hFile,
406 &IoStatusBlock,
407 &FileCompression,
408 sizeof(FILE_COMPRESSION_INFORMATION),
409 FileCompressionInformation);
410 if (!NT_SUCCESS(errCode))
411 {
412 CloseHandle(hFile);
413 SetLastErrorByStatus(errCode);
414 return 0;
415 }
416 CloseHandle(hFile);
417 return 0;
418 }
419
420
421 WINBOOL STDCALL
422 GetFileInformationByHandle(HANDLE hFile,
423 LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
424 {
425 struct
426 {
427 FILE_FS_VOLUME_INFORMATION FileFsVolume;
428 WCHAR Name[255];
429 }
430 FileFsVolume;
431
432 FILE_BASIC_INFORMATION FileBasic;
433 FILE_INTERNAL_INFORMATION FileInternal;
434 FILE_STANDARD_INFORMATION FileStandard;
435 NTSTATUS errCode;
436 IO_STATUS_BLOCK IoStatusBlock;
437
438 errCode = NtQueryInformationFile(hFile,
439 &IoStatusBlock,
440 &FileBasic,
441 sizeof(FILE_BASIC_INFORMATION),
442 FileBasicInformation);
443 if (!NT_SUCCESS(errCode))
444 {
445 SetLastErrorByStatus(errCode);
446 return FALSE;
447 }
448
449 lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes;
450 memcpy(&lpFileInformation->ftCreationTime,&FileBasic.CreationTime,sizeof(LARGE_INTEGER));
451 memcpy(&lpFileInformation->ftLastAccessTime,&FileBasic.LastAccessTime,sizeof(LARGE_INTEGER));
452 memcpy(&lpFileInformation->ftLastWriteTime, &FileBasic.LastWriteTime,sizeof(LARGE_INTEGER));
453
454 errCode = NtQueryInformationFile(hFile,
455 &IoStatusBlock,
456 &FileInternal,
457 sizeof(FILE_INTERNAL_INFORMATION),
458 FileInternalInformation);
459 if (!NT_SUCCESS(errCode))
460 {
461 SetLastErrorByStatus(errCode);
462 return FALSE;
463 }
464
465 lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart;
466 lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart;
467
468 errCode = NtQueryVolumeInformationFile(hFile,
469 &IoStatusBlock,
470 &FileFsVolume,
471 sizeof(FileFsVolume),
472 FileFsVolumeInformation);
473 if (!NT_SUCCESS(errCode))
474 {
475 SetLastErrorByStatus(errCode);
476 return FALSE;
477 }
478
479 lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber;
480
481 errCode = NtQueryInformationFile(hFile,
482 &IoStatusBlock,
483 &FileStandard,
484 sizeof(FILE_STANDARD_INFORMATION),
485 FileStandardInformation);
486 if (!NT_SUCCESS(errCode))
487 {
488 SetLastErrorByStatus(errCode);
489 return FALSE;
490 }
491
492 lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks;
493 lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
494 lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart;
495
496 return TRUE;
497 }
498
499
500 DWORD STDCALL
501 GetFileAttributesA(LPCSTR lpFileName)
502 {
503 UNICODE_STRING FileNameU;
504 ANSI_STRING FileName;
505 WINBOOL Result;
506
507 RtlInitAnsiString (&FileName,
508 (LPSTR)lpFileName);
509
510 /* convert ansi (or oem) string to unicode */
511 if (bIsFileApiAnsi)
512 RtlAnsiStringToUnicodeString (&FileNameU,
513 &FileName,
514 TRUE);
515 else
516 RtlOemStringToUnicodeString (&FileNameU,
517 &FileName,
518 TRUE);
519
520 Result = GetFileAttributesW (FileNameU.Buffer);
521
522 RtlFreeUnicodeString (&FileNameU);
523
524 return Result;
525 }
526
527
528 DWORD STDCALL
529 GetFileAttributesW(LPCWSTR lpFileName)
530 {
531 IO_STATUS_BLOCK IoStatusBlock;
532 FILE_BASIC_INFORMATION FileBasic;
533 HANDLE hFile;
534 NTSTATUS errCode;
535
536 hFile = CreateFileW(lpFileName,
537 FILE_READ_ATTRIBUTES,
538 FILE_SHARE_READ,
539 NULL,
540 OPEN_EXISTING,
541 FILE_ATTRIBUTE_NORMAL,
542 NULL);
543 if (hFile == INVALID_HANDLE_VALUE)
544 {
545 return 0xFFFFFFFF;
546 }
547
548 errCode = NtQueryInformationFile(hFile,
549 &IoStatusBlock,
550 &FileBasic,
551 sizeof(FILE_BASIC_INFORMATION),
552 FileBasicInformation);
553 if (!NT_SUCCESS(errCode))
554 {
555 CloseHandle(hFile);
556 SetLastErrorByStatus(errCode);
557 return 0xFFFFFFFF;
558 }
559 CloseHandle(hFile);
560 return (DWORD)FileBasic.FileAttributes;
561 }
562
563
564 WINBOOL STDCALL
565 SetFileAttributesA(LPCSTR lpFileName,
566 DWORD dwFileAttributes)
567 {
568 UNICODE_STRING FileNameU;
569 ANSI_STRING FileName;
570 WINBOOL Result;
571
572 RtlInitAnsiString(&FileName,
573 (LPSTR)lpFileName);
574
575 /* convert ansi (or oem) string to unicode */
576 if (bIsFileApiAnsi)
577 RtlAnsiStringToUnicodeString(&FileNameU,
578 &FileName,
579 TRUE);
580 else
581 RtlOemStringToUnicodeString(&FileNameU,
582 &FileName,
583 TRUE);
584
585 Result = SetFileAttributesW(FileNameU.Buffer,
586 dwFileAttributes);
587
588 RtlFreeUnicodeString(&FileNameU);
589
590 return Result;
591 }
592
593
594 WINBOOL STDCALL
595 SetFileAttributesW(LPCWSTR lpFileName,
596 DWORD dwFileAttributes)
597 {
598 IO_STATUS_BLOCK IoStatusBlock;
599 FILE_BASIC_INFORMATION FileBasic;
600 HANDLE hFile;
601 NTSTATUS errCode;
602
603 hFile = CreateFileW(lpFileName,
604 FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
605 FILE_SHARE_READ,
606 NULL,
607 OPEN_EXISTING,
608 FILE_ATTRIBUTE_NORMAL,
609 NULL);
610
611 errCode = NtQueryInformationFile(hFile,
612 &IoStatusBlock,
613 &FileBasic,
614 sizeof(FILE_BASIC_INFORMATION),
615 FileBasicInformation);
616 if (!NT_SUCCESS(errCode))
617 {
618 CloseHandle(hFile);
619 SetLastErrorByStatus(errCode);
620 return FALSE;
621 }
622 FileBasic.FileAttributes = dwFileAttributes;
623 errCode = NtSetInformationFile(hFile,
624 &IoStatusBlock,
625 &FileBasic,
626 sizeof(FILE_BASIC_INFORMATION),
627 FileBasicInformation);
628 if (!NT_SUCCESS(errCode))
629 {
630 CloseHandle(hFile);
631 SetLastErrorByStatus(errCode);
632 return FALSE;
633 }
634 CloseHandle(hFile);
635 return TRUE;
636 }
637
638
639 UINT STDCALL
640 GetTempFileNameA(LPCSTR lpPathName,
641 LPCSTR lpPrefixString,
642 UINT uUnique,
643 LPSTR lpTempFileName)
644 {
645 HANDLE hFile;
646 UINT unique = uUnique;
647 UINT len;
648 const char *format = "%.*s\\~%.3s%4.4x.TMP";
649
650 DPRINT("GetTempFileNameA(lpPathName %s, lpPrefixString %.*s, "
651 "uUnique %x, lpTempFileName %x)\n", lpPathName, 4,
652 lpPrefixString, uUnique, lpTempFileName);
653
654 if (lpPathName == NULL)
655 return 0;
656
657 len = strlen(lpPathName);
658 if (len > 0 && (lpPathName[len-1] == '\\' || lpPathName[len-1] == '/'))
659 len--;
660
661 if (uUnique == 0)
662 uUnique = GetCurrentTime();
663
664 sprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,uUnique);
665
666 if (unique)
667 return uUnique;
668
669 while ((hFile = CreateFileA(lpTempFileName, GENERIC_WRITE, 0, NULL,
670 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
671 0)) == INVALID_HANDLE_VALUE)
672 {
673 if (GetLastError() != ERROR_ALREADY_EXISTS)
674 {
675 return 0;
676 }
677 sprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,++uUnique);
678 }
679 CloseHandle(hFile);
680 return uUnique;
681 }
682
683
684 UINT STDCALL
685 GetTempFileNameW(LPCWSTR lpPathName,
686 LPCWSTR lpPrefixString,
687 UINT uUnique,
688 LPWSTR lpTempFileName)
689 {
690 HANDLE hFile;
691 UINT unique = uUnique;
692 UINT len;
693 const WCHAR *format = L"%.*S\\~%.3S%4.4x.TMP";
694
695 DPRINT("GetTempFileNameW(lpPathName %S, lpPrefixString %.*S, "
696 "uUnique %x, lpTempFileName %x)\n", lpPathName, 4,
697 lpPrefixString, uUnique, lpTempFileName);
698
699 if (lpPathName == NULL)
700 return 0;
701
702 len = wcslen(lpPathName);
703 if (len > 0 && (lpPathName[len-1] == L'\\' || lpPathName[len-1] == L'/'))
704 len--;
705
706 if (uUnique == 0)
707 uUnique = GetCurrentTime();
708
709 swprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,uUnique);
710
711 if (unique)
712 return uUnique;
713
714 while ((hFile = CreateFileW(lpTempFileName, GENERIC_WRITE, 0, NULL,
715 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
716 0)) == INVALID_HANDLE_VALUE)
717 {
718 if (GetLastError() != ERROR_ALREADY_EXISTS)
719 {
720 return 0;
721 }
722 swprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,++uUnique);
723 }
724 CloseHandle(hFile);
725 return uUnique;
726 }
727
728
729 WINBOOL STDCALL
730 GetFileTime(HANDLE hFile,
731 LPFILETIME lpCreationTime,
732 LPFILETIME lpLastAccessTime,
733 LPFILETIME lpLastWriteTime)
734 {
735 IO_STATUS_BLOCK IoStatusBlock;
736 FILE_BASIC_INFORMATION FileBasic;
737 NTSTATUS Status;
738
739 Status = NtQueryInformationFile(hFile,
740 &IoStatusBlock,
741 &FileBasic,
742 sizeof(FILE_BASIC_INFORMATION),
743 FileBasicInformation);
744 if (!NT_SUCCESS(Status))
745 {
746 SetLastErrorByStatus(Status);
747 return FALSE;
748 }
749
750 if (lpCreationTime)
751 memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
752 if (lpLastAccessTime)
753 memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
754 if (lpLastWriteTime)
755 memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
756
757 return TRUE;
758 }
759
760
761 WINBOOL STDCALL
762 SetFileTime(HANDLE hFile,
763 CONST FILETIME *lpCreationTime,
764 CONST FILETIME *lpLastAccessTime,
765 CONST FILETIME *lpLastWriteTime)
766 {
767 FILE_BASIC_INFORMATION FileBasic;
768 IO_STATUS_BLOCK IoStatusBlock;
769 NTSTATUS Status;
770
771 Status = NtQueryInformationFile(hFile,
772 &IoStatusBlock,
773 &FileBasic,
774 sizeof(FILE_BASIC_INFORMATION),
775 FileBasicInformation);
776 if (!NT_SUCCESS(Status))
777 {
778 SetLastErrorByStatus(Status);
779 return FALSE;
780 }
781
782 if (lpCreationTime)
783 memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
784 if (lpLastAccessTime)
785 memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
786 if (lpLastWriteTime)
787 memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
788
789 // should i initialize changetime ???
790
791 Status = NtSetInformationFile(hFile,
792 &IoStatusBlock,
793 &FileBasic,
794 sizeof(FILE_BASIC_INFORMATION),
795 FileBasicInformation);
796 if (!NT_SUCCESS(Status))
797 {
798 SetLastErrorByStatus(Status);
799 return FALSE;
800 }
801
802 return TRUE;
803 }
804
805
806 /*
807 The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
808 */
809 WINBOOL STDCALL
810 SetEndOfFile(HANDLE hFile)
811 {
812 IO_STATUS_BLOCK IoStatusBlock;
813 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
814 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
815 FILE_POSITION_INFORMATION FilePosInfo;
816 NTSTATUS Status;
817
818 //get current position
819 Status = NtQueryInformationFile(
820 hFile,
821 &IoStatusBlock,
822 &FilePosInfo,
823 sizeof(FILE_POSITION_INFORMATION),
824 FilePositionInformation
825 );
826
827 if (!NT_SUCCESS(Status)){
828 SetLastErrorByStatus(Status);
829 return FALSE;
830 }
831
832 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
833
834 /*
835 NOTE:
836 This call is not supposed to free up any space after the eof marker
837 if the file gets truncated. We have to deallocate the space explicitly afterwards.
838 But...most file systems dispatch both FileEndOfFileInformation
839 and FileAllocationInformation as they were the same command.
840
841 */
842 Status = NtSetInformationFile(
843 hFile,
844 &IoStatusBlock, //out
845 &EndOfFileInfo,
846 sizeof(FILE_END_OF_FILE_INFORMATION),
847 FileEndOfFileInformation
848 );
849
850 if (!NT_SUCCESS(Status)){
851 SetLastErrorByStatus(Status);
852 return FALSE;
853 }
854
855 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
856
857
858 Status = NtSetInformationFile(
859 hFile,
860 &IoStatusBlock, //out
861 &FileAllocationInfo,
862 sizeof(FILE_ALLOCATION_INFORMATION),
863 FileAllocationInformation
864 );
865
866 if (!NT_SUCCESS(Status)){
867 SetLastErrorByStatus(Status);
868 return FALSE;
869 }
870
871 return TRUE;
872
873 }
874
875 /* EOF */