update for HEAD-2003050101
[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         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 */