branch update for HEAD-2003021201
[reactos.git] / lib / kernel32 / file / file.c
1 /* $Id$
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
258           break;
259
260         case STD_OUTPUT_HANDLE:
261           hFile = NtCurrentPeb()->ProcessParameters->hStdOutput;
262
263           break;
264
265         case STD_ERROR_HANDLE:
266           hFile = NtCurrentPeb()->ProcessParameters->hStdError;
267
268           break;
269      }
270
271    /* check console handles */
272    if (IsConsoleHandle(hFile))
273      {
274 //      if (VerifyConsoleHandle(hFile))
275           return FILE_TYPE_CHAR;
276      }
277
278    Status = NtQueryVolumeInformationFile(hFile,
279                                          &StatusBlock,
280                                          &DeviceInfo,
281                                          sizeof(FILE_FS_DEVICE_INFORMATION),
282                                          FileFsDeviceInformation);
283    if (!NT_SUCCESS(Status))
284      {
285         SetLastErrorByStatus(Status);
286         return FILE_TYPE_UNKNOWN;
287      }
288
289    switch (DeviceInfo.DeviceType)
290      {
291         case FILE_DEVICE_CD_ROM:
292         case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
293         case FILE_DEVICE_CONTROLLER:
294         case FILE_DEVICE_DATALINK:
295         case FILE_DEVICE_DFS:
296         case FILE_DEVICE_DISK:
297         case FILE_DEVICE_DISK_FILE_SYSTEM:
298         case FILE_DEVICE_VIRTUAL_DISK:
299           return FILE_TYPE_DISK;
300
301         case FILE_DEVICE_KEYBOARD:
302         case FILE_DEVICE_MOUSE:
303         case FILE_DEVICE_NULL:
304         case FILE_DEVICE_PARALLEL_PORT:
305         case FILE_DEVICE_PRINTER:
306         case FILE_DEVICE_SERIAL_PORT:
307         case FILE_DEVICE_SCREEN:
308         case FILE_DEVICE_SOUND:
309         case FILE_DEVICE_MODEM:
310           return FILE_TYPE_CHAR;
311
312         case FILE_DEVICE_NAMED_PIPE:
313           return FILE_TYPE_PIPE;
314      }
315
316    return FILE_TYPE_UNKNOWN;
317 }
318
319
320 DWORD STDCALL
321 GetFileSize(HANDLE hFile,
322             LPDWORD lpFileSizeHigh)
323 {
324    NTSTATUS errCode;
325    FILE_STANDARD_INFORMATION FileStandard;
326    IO_STATUS_BLOCK IoStatusBlock;
327
328    errCode = NtQueryInformationFile(hFile,
329                                     &IoStatusBlock,
330                                     &FileStandard,
331                                     sizeof(FILE_STANDARD_INFORMATION),
332                                     FileStandardInformation);
333    if (!NT_SUCCESS(errCode))
334      {
335         SetLastErrorByStatus(errCode);
336         if ( lpFileSizeHigh == NULL )
337           {
338              return -1;
339           }
340         else
341           {
342              return 0;
343           }
344      }
345    if ( lpFileSizeHigh != NULL )
346      *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
347
348    return FileStandard.EndOfFile.u.LowPart;
349 }
350
351
352 DWORD STDCALL
353 GetCompressedFileSizeA(LPCSTR lpFileName,
354                        LPDWORD lpFileSizeHigh)
355 {
356    UNICODE_STRING FileNameU;
357    ANSI_STRING FileName;
358    DWORD Size;
359
360    RtlInitAnsiString(&FileName,
361                      (LPSTR)lpFileName);
362
363    /* convert ansi (or oem) string to unicode */
364    if (bIsFileApiAnsi)
365      RtlAnsiStringToUnicodeString(&FileNameU,
366                                   &FileName,
367                                   TRUE);
368    else
369      RtlOemStringToUnicodeString(&FileNameU,
370                                  &FileName,
371                                  TRUE);
372
373    Size = GetCompressedFileSizeW(FileNameU.Buffer,
374                                  lpFileSizeHigh);
375
376    RtlFreeUnicodeString (&FileNameU);
377
378    return Size;
379 }
380
381
382 DWORD STDCALL
383 GetCompressedFileSizeW(LPCWSTR lpFileName,
384                        LPDWORD lpFileSizeHigh)
385 {
386    FILE_COMPRESSION_INFORMATION FileCompression;
387    NTSTATUS errCode;
388    IO_STATUS_BLOCK IoStatusBlock;
389    HANDLE hFile;
390    
391    hFile = CreateFileW(lpFileName,
392                        GENERIC_READ,
393                        FILE_SHARE_READ,
394                        NULL,
395                        OPEN_EXISTING,
396                        FILE_ATTRIBUTE_NORMAL,
397                        NULL);
398
399    errCode = NtQueryInformationFile(hFile,
400                                     &IoStatusBlock,
401                                     &FileCompression,
402                                     sizeof(FILE_COMPRESSION_INFORMATION),
403                                     FileCompressionInformation);
404    if (!NT_SUCCESS(errCode))
405      {
406         CloseHandle(hFile);
407         SetLastErrorByStatus(errCode);
408         return INVALID_FILE_SIZE;
409      }
410    CloseHandle(hFile);
411
412    if(lpFileSizeHigh)
413     *lpFileSizeHigh = FileCompression.CompressedFileSize.u.HighPart;
414
415    return FileCompression.CompressedFileSize.u.LowPart;
416 }
417
418
419 WINBOOL STDCALL
420 GetFileInformationByHandle(HANDLE hFile,
421                            LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
422 {
423    struct
424    {
425         FILE_FS_VOLUME_INFORMATION FileFsVolume;
426         WCHAR Name[255];
427    }
428    FileFsVolume;
429
430    FILE_BASIC_INFORMATION FileBasic;
431    FILE_INTERNAL_INFORMATION FileInternal;
432    FILE_STANDARD_INFORMATION FileStandard;
433    NTSTATUS errCode;
434    IO_STATUS_BLOCK IoStatusBlock;
435
436    errCode = NtQueryInformationFile(hFile,
437                                     &IoStatusBlock,
438                                     &FileBasic,
439                                     sizeof(FILE_BASIC_INFORMATION),
440                                     FileBasicInformation);
441    if (!NT_SUCCESS(errCode))
442      {
443         SetLastErrorByStatus(errCode);
444         return FALSE;
445      }
446
447    lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes;
448    memcpy(&lpFileInformation->ftCreationTime,&FileBasic.CreationTime,sizeof(LARGE_INTEGER));
449    memcpy(&lpFileInformation->ftLastAccessTime,&FileBasic.LastAccessTime,sizeof(LARGE_INTEGER));
450    memcpy(&lpFileInformation->ftLastWriteTime, &FileBasic.LastWriteTime,sizeof(LARGE_INTEGER));
451
452    errCode = NtQueryInformationFile(hFile,
453                                     &IoStatusBlock,
454                                     &FileInternal,
455                                     sizeof(FILE_INTERNAL_INFORMATION),
456                                     FileInternalInformation);
457    if (!NT_SUCCESS(errCode))
458      {
459         SetLastErrorByStatus(errCode);
460         return FALSE;
461      }
462
463    lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart;
464    lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart;
465
466    errCode = NtQueryVolumeInformationFile(hFile,
467                                           &IoStatusBlock,
468                                           &FileFsVolume,
469                                           sizeof(FileFsVolume),
470                                           FileFsVolumeInformation);
471    if (!NT_SUCCESS(errCode))
472      {
473         SetLastErrorByStatus(errCode);
474         return FALSE;
475      }
476
477    lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber;
478
479    errCode = NtQueryInformationFile(hFile,
480                                     &IoStatusBlock,
481                                     &FileStandard,
482                                     sizeof(FILE_STANDARD_INFORMATION),
483                                     FileStandardInformation);
484    if (!NT_SUCCESS(errCode))
485      {
486         SetLastErrorByStatus(errCode);
487         return FALSE;
488      }
489
490    lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks;
491    lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
492    lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart;
493
494    return TRUE;
495 }
496
497
498 DWORD STDCALL
499 GetFileAttributesA(LPCSTR lpFileName)
500 {
501         UNICODE_STRING FileNameU;
502         ANSI_STRING FileName;
503         WINBOOL Result;
504
505         RtlInitAnsiString (&FileName,
506                            (LPSTR)lpFileName);
507
508         /* convert ansi (or oem) string to unicode */
509         if (bIsFileApiAnsi)
510                 RtlAnsiStringToUnicodeString (&FileNameU,
511                                               &FileName,
512                                               TRUE);
513         else
514                 RtlOemStringToUnicodeString (&FileNameU,
515                                              &FileName,
516                                              TRUE);
517
518         Result = GetFileAttributesW (FileNameU.Buffer);
519
520         RtlFreeUnicodeString (&FileNameU);
521
522         return Result;
523 }
524
525
526 DWORD STDCALL
527 GetFileAttributesW(LPCWSTR lpFileName)
528 {
529    IO_STATUS_BLOCK IoStatusBlock;
530    FILE_BASIC_INFORMATION FileBasic;
531    HANDLE hFile;
532    NTSTATUS errCode;
533
534    hFile = CreateFileW(lpFileName,
535                        FILE_READ_ATTRIBUTES,
536                        FILE_SHARE_READ,
537                        NULL,
538                        OPEN_EXISTING,
539                        FILE_ATTRIBUTE_NORMAL,
540                        NULL);
541    if (hFile == INVALID_HANDLE_VALUE)
542      {
543         return 0xFFFFFFFF;
544      }
545
546    errCode = NtQueryInformationFile(hFile,
547                                     &IoStatusBlock,
548                                     &FileBasic,
549                                     sizeof(FILE_BASIC_INFORMATION),
550                                     FileBasicInformation);
551    if (!NT_SUCCESS(errCode))
552      {
553         CloseHandle(hFile);
554         SetLastErrorByStatus(errCode);
555         return 0xFFFFFFFF;
556      }
557    CloseHandle(hFile);
558    return (DWORD)FileBasic.FileAttributes;
559 }
560
561
562 WINBOOL STDCALL
563 SetFileAttributesA(LPCSTR lpFileName,
564                    DWORD dwFileAttributes)
565 {
566    UNICODE_STRING FileNameU;
567    ANSI_STRING FileName;
568    WINBOOL Result;
569
570    RtlInitAnsiString(&FileName,
571                      (LPSTR)lpFileName);
572
573    /* convert ansi (or oem) string to unicode */
574    if (bIsFileApiAnsi)
575      RtlAnsiStringToUnicodeString(&FileNameU,
576                                   &FileName,
577                                   TRUE);
578    else
579      RtlOemStringToUnicodeString(&FileNameU,
580                                  &FileName,
581                                  TRUE);
582
583    Result = SetFileAttributesW(FileNameU.Buffer,
584                                dwFileAttributes);
585
586    RtlFreeUnicodeString(&FileNameU);
587
588    return Result;
589 }
590
591
592 WINBOOL STDCALL
593 SetFileAttributesW(LPCWSTR lpFileName,
594                    DWORD dwFileAttributes)
595 {
596    IO_STATUS_BLOCK IoStatusBlock;
597    FILE_BASIC_INFORMATION FileBasic;
598    HANDLE hFile;
599    NTSTATUS errCode;
600    
601    hFile = CreateFileW(lpFileName,
602                        FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
603                        FILE_SHARE_READ,
604                        NULL,
605                        OPEN_EXISTING,
606                        FILE_ATTRIBUTE_NORMAL,
607                        NULL);
608    if (INVALID_HANDLE_VALUE == hFile)
609      {
610         DPRINT("SetFileAttributes CreateFileW failed with code %d\n", GetLastError());
611         return FALSE;
612      }
613
614    errCode = NtQueryInformationFile(hFile,
615                                     &IoStatusBlock,
616                                     &FileBasic,
617                                     sizeof(FILE_BASIC_INFORMATION),
618                                     FileBasicInformation);
619    if (!NT_SUCCESS(errCode))
620      {
621         CloseHandle(hFile);
622         DPRINT("SetFileAttributes NtQueryInformationFile failed with status 0x%08x\n", errCode);
623         SetLastErrorByStatus(errCode);
624         return FALSE;
625      }
626    FileBasic.FileAttributes = dwFileAttributes;
627    errCode = NtSetInformationFile(hFile,
628                                   &IoStatusBlock,
629                                   &FileBasic,
630                                   sizeof(FILE_BASIC_INFORMATION),
631                                   FileBasicInformation);
632    if (!NT_SUCCESS(errCode))
633      {
634         CloseHandle(hFile);
635         DPRINT("SetFileAttributes NtSetInformationFile failed with status 0x%08x\n", errCode);
636         SetLastErrorByStatus(errCode);
637         return FALSE;
638      }
639    CloseHandle(hFile);
640    return TRUE;
641 }
642
643
644 UINT STDCALL
645 GetTempFileNameA(LPCSTR lpPathName,
646                  LPCSTR lpPrefixString,
647                  UINT uUnique,
648                  LPSTR lpTempFileName)
649 {
650    HANDLE hFile;
651    UINT unique = uUnique;
652    UINT len;
653    const char *format = "%.*s\\~%.3s%4.4x.TMP";
654
655    DPRINT("GetTempFileNameA(lpPathName %s, lpPrefixString %.*s, "
656           "uUnique %x, lpTempFileName %x)\n", lpPathName, 4, 
657           lpPrefixString, uUnique, lpTempFileName);
658   
659    if (lpPathName == NULL)
660      return 0;
661
662    len = strlen(lpPathName);
663    if (len > 0 && (lpPathName[len-1] == '\\' || lpPathName[len-1] == '/'))
664      len--;
665
666    if (uUnique == 0)
667      uUnique = GetCurrentTime();
668    
669    sprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,uUnique);
670    
671    if (unique)
672      return uUnique;
673    
674    while ((hFile = CreateFileA(lpTempFileName, GENERIC_WRITE, 0, NULL,
675                                CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
676                                0)) == INVALID_HANDLE_VALUE)
677    {
678       if (GetLastError() != ERROR_ALREADY_EXISTS)
679       {
680          return 0;
681       }
682       sprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,++uUnique);
683    }
684    CloseHandle(hFile);
685    return uUnique;
686 }
687
688
689 UINT STDCALL
690 GetTempFileNameW(LPCWSTR lpPathName,
691                  LPCWSTR lpPrefixString,
692                  UINT uUnique,
693                  LPWSTR lpTempFileName)
694 {
695    HANDLE hFile;
696    UINT unique = uUnique;
697    UINT len;
698    const WCHAR *format = L"%.*S\\~%.3S%4.4x.TMP";
699    
700    DPRINT("GetTempFileNameW(lpPathName %S, lpPrefixString %.*S, "
701           "uUnique %x, lpTempFileName %x)\n", lpPathName, 4, 
702           lpPrefixString, uUnique, lpTempFileName);
703
704    if (lpPathName == NULL)
705      return 0;
706
707    len = wcslen(lpPathName);
708    if (len > 0 && (lpPathName[len-1] == L'\\' || lpPathName[len-1] == L'/'))
709      len--;
710    
711    if (uUnique == 0)
712      uUnique = GetCurrentTime();
713    
714    swprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,uUnique);
715    
716    if (unique)
717      return uUnique;
718   
719    while ((hFile = CreateFileW(lpTempFileName, GENERIC_WRITE, 0, NULL,
720                                CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
721                                0)) == INVALID_HANDLE_VALUE)
722    {
723       if (GetLastError() != ERROR_ALREADY_EXISTS)
724       {
725          return 0;
726       }
727       swprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,++uUnique);
728    }
729    CloseHandle(hFile);
730    return uUnique;
731 }
732
733
734 WINBOOL STDCALL
735 GetFileTime(HANDLE hFile,
736             LPFILETIME lpCreationTime,
737             LPFILETIME lpLastAccessTime,
738             LPFILETIME lpLastWriteTime)
739 {
740    IO_STATUS_BLOCK IoStatusBlock;
741    FILE_BASIC_INFORMATION FileBasic;
742    NTSTATUS Status;
743
744    Status = NtQueryInformationFile(hFile,
745                                    &IoStatusBlock,
746                                    &FileBasic,
747                                    sizeof(FILE_BASIC_INFORMATION),
748                                    FileBasicInformation);
749    if (!NT_SUCCESS(Status))
750      {
751         SetLastErrorByStatus(Status);
752         return FALSE;
753      }
754
755    if (lpCreationTime)
756      memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
757    if (lpLastAccessTime)
758      memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
759    if (lpLastWriteTime)
760      memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
761
762    return TRUE;
763 }
764
765
766 WINBOOL STDCALL
767 SetFileTime(HANDLE hFile,
768             CONST FILETIME *lpCreationTime,
769             CONST FILETIME *lpLastAccessTime,
770             CONST FILETIME *lpLastWriteTime)
771 {
772    FILE_BASIC_INFORMATION FileBasic;
773    IO_STATUS_BLOCK IoStatusBlock;
774    NTSTATUS Status;
775
776    Status = NtQueryInformationFile(hFile,
777                                    &IoStatusBlock,
778                                    &FileBasic,
779                                    sizeof(FILE_BASIC_INFORMATION),
780                                    FileBasicInformation);
781    if (!NT_SUCCESS(Status))
782      {
783         SetLastErrorByStatus(Status);
784         return FALSE;
785      }
786
787    if (lpCreationTime)
788      memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
789    if (lpLastAccessTime)
790      memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
791    if (lpLastWriteTime)
792      memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
793
794    // should i initialize changetime ???
795
796    Status = NtSetInformationFile(hFile,
797                                  &IoStatusBlock,
798                                  &FileBasic,
799                                  sizeof(FILE_BASIC_INFORMATION),
800                                  FileBasicInformation);
801    if (!NT_SUCCESS(Status))
802      {
803         SetLastErrorByStatus(Status);
804         return FALSE;
805      }
806    
807    return TRUE;
808 }
809
810
811 /*
812 The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
813 */
814 WINBOOL STDCALL
815 SetEndOfFile(HANDLE hFile)
816 {
817         IO_STATUS_BLOCK  IoStatusBlock;
818         FILE_END_OF_FILE_INFORMATION    EndOfFileInfo;
819         FILE_ALLOCATION_INFORMATION             FileAllocationInfo;
820         FILE_POSITION_INFORMATION                FilePosInfo;
821         NTSTATUS Status;
822
823         //get current position
824         Status = NtQueryInformationFile(
825                                         hFile,
826                                         &IoStatusBlock,
827                                         &FilePosInfo,
828                                         sizeof(FILE_POSITION_INFORMATION),
829                                         FilePositionInformation
830                                         );
831
832         if (!NT_SUCCESS(Status)){
833                 SetLastErrorByStatus(Status);
834                 return FALSE;
835         }
836
837         EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
838
839         /*
840         NOTE: 
841         This call is not supposed to free up any space after the eof marker
842         if the file gets truncated. We have to deallocate the space explicitly afterwards.
843         But...most file systems dispatch both FileEndOfFileInformation 
844         and FileAllocationInformation as they were the same     command.
845
846         */
847         Status = NtSetInformationFile(
848                                                 hFile,
849                                                 &IoStatusBlock,  //out
850                                                 &EndOfFileInfo,
851                                                 sizeof(FILE_END_OF_FILE_INFORMATION),
852                                                 FileEndOfFileInformation
853                                                 );
854
855         if (!NT_SUCCESS(Status)){
856                 SetLastErrorByStatus(Status);
857                 return FALSE;
858         }
859
860         FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
861
862
863         Status = NtSetInformationFile(
864                                                 hFile,
865                                                 &IoStatusBlock,  //out
866                                                 &FileAllocationInfo,
867                                                 sizeof(FILE_ALLOCATION_INFORMATION),
868                                                 FileAllocationInformation
869                                                 );
870
871         if (!NT_SUCCESS(Status)){
872                 SetLastErrorByStatus(Status);
873                 return FALSE;
874         }
875         
876         return TRUE;
877
878 }
879
880 /* EOF */