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