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