migrate substitution keywords to SVN
[reactos.git] / reactos / 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 "../include/debug.h"
19
20
21 /* GLOBALS ******************************************************************/
22
23 BOOL 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 BOOL 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 if ((uStyle & OF_CREATE) == OF_CREATE)
85 {
86 DWORD Sharing;
87 switch (uStyle & 0x70)
88 {
89 case OF_SHARE_EXCLUSIVE: Sharing = 0; break;
90 case OF_SHARE_DENY_WRITE: Sharing = FILE_SHARE_READ; break;
91 case OF_SHARE_DENY_READ: Sharing = FILE_SHARE_WRITE; break;
92 case OF_SHARE_DENY_NONE:
93 case OF_SHARE_COMPAT:
94 default:
95 Sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
96 }
97 return (HFILE) CreateFileA (lpFileName,
98 GENERIC_READ | GENERIC_WRITE,
99 Sharing,
100 NULL,
101 CREATE_ALWAYS,
102 FILE_ATTRIBUTE_NORMAL,
103 0);
104 }
105
106 RtlInitAnsiString (&FileName, (LPSTR)lpFileName);
107
108 /* convert ansi (or oem) string to unicode */
109 if (bIsFileApiAnsi)
110 RtlAnsiStringToUnicodeString (&FileNameU, &FileName, TRUE);
111 else
112 RtlOemStringToUnicodeString (&FileNameU, &FileName, TRUE);
113
114 Len = SearchPathW (NULL,
115 FileNameU.Buffer,
116 NULL,
117 OFS_MAXPATHNAME,
118 PathNameW,
119 &FilePart);
120
121 RtlFreeUnicodeString(&FileNameU);
122
123 if (Len == 0 || Len > OFS_MAXPATHNAME)
124 {
125 return (HFILE)INVALID_HANDLE_VALUE;
126 }
127
128 FileName.Buffer = lpReOpenBuff->szPathName;
129 FileName.Length = 0;
130 FileName.MaximumLength = OFS_MAXPATHNAME;
131
132 RtlInitUnicodeString(&FileNameU, PathNameW);
133
134 /* convert unicode string to ansi (or oem) */
135 if (bIsFileApiAnsi)
136 RtlUnicodeStringToAnsiString (&FileName, &FileNameU, FALSE);
137 else
138 RtlUnicodeStringToOemString (&FileName, &FileNameU, FALSE);
139
140 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)PathNameW,
141 &FileNameString,
142 NULL,
143 NULL))
144 {
145 return (HFILE)INVALID_HANDLE_VALUE;
146 }
147
148 // FILE_SHARE_READ
149 // FILE_NO_INTERMEDIATE_BUFFERING
150
151 if ((uStyle & OF_PARSE) == OF_PARSE)
152 {
153 RtlFreeUnicodeString(&FileNameString);
154 return (HFILE)NULL;
155 }
156
157 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
158 ObjectAttributes.RootDirectory = NULL;
159 ObjectAttributes.ObjectName = &FileNameString;
160 ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT;
161 ObjectAttributes.SecurityDescriptor = NULL;
162 ObjectAttributes.SecurityQualityOfService = NULL;
163
164 errCode = NtOpenFile (&FileHandle,
165 GENERIC_READ|SYNCHRONIZE,
166 &ObjectAttributes,
167 &IoStatusBlock,
168 FILE_SHARE_READ,
169 FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT);
170
171 RtlFreeUnicodeString(&FileNameString);
172
173 lpReOpenBuff->nErrCode = RtlNtStatusToDosError(errCode);
174
175 if (!NT_SUCCESS(errCode))
176 {
177 SetLastErrorByStatus (errCode);
178 return (HFILE)INVALID_HANDLE_VALUE;
179 }
180
181 return (HFILE)FileHandle;
182 }
183
184
185 /*
186 * @implemented
187 */
188 BOOL STDCALL
189 FlushFileBuffers(HANDLE hFile)
190 {
191 NTSTATUS errCode;
192 IO_STATUS_BLOCK IoStatusBlock;
193
194 if (IsConsoleHandle(hFile))
195 {
196 return FALSE;
197 }
198
199 errCode = NtFlushBuffersFile(hFile,
200 &IoStatusBlock);
201 if (!NT_SUCCESS(errCode))
202 {
203 SetLastErrorByStatus(errCode);
204 return(FALSE);
205 }
206 return(TRUE);
207 }
208
209
210 /*
211 * @implemented
212 */
213 DWORD STDCALL
214 SetFilePointer(HANDLE hFile,
215 LONG lDistanceToMove,
216 PLONG lpDistanceToMoveHigh,
217 DWORD dwMoveMethod)
218 {
219 FILE_POSITION_INFORMATION FilePosition;
220 FILE_STANDARD_INFORMATION FileStandard;
221 NTSTATUS errCode;
222 IO_STATUS_BLOCK IoStatusBlock;
223 LARGE_INTEGER Distance;
224
225 DPRINT("SetFilePointer(hFile %x, lDistanceToMove %d, dwMoveMethod %d)\n",
226 hFile,lDistanceToMove,dwMoveMethod);
227
228 if(IsConsoleHandle(hFile))
229 {
230 SetLastError(ERROR_INVALID_HANDLE);
231 return -1;
232 }
233
234 Distance.u.LowPart = lDistanceToMove;
235 if (lpDistanceToMoveHigh)
236 {
237 Distance.u.HighPart = *lpDistanceToMoveHigh;
238 }
239 else if (lDistanceToMove >= 0)
240 {
241 Distance.u.HighPart = 0;
242 }
243 else
244 {
245 Distance.u.HighPart = -1;
246 }
247
248 switch(dwMoveMethod)
249 {
250 case FILE_CURRENT:
251 NtQueryInformationFile(hFile,
252 &IoStatusBlock,
253 &FilePosition,
254 sizeof(FILE_POSITION_INFORMATION),
255 FilePositionInformation);
256 FilePosition.CurrentByteOffset.QuadPart += Distance.QuadPart;
257 break;
258 case FILE_END:
259 NtQueryInformationFile(hFile,
260 &IoStatusBlock,
261 &FileStandard,
262 sizeof(FILE_STANDARD_INFORMATION),
263 FileStandardInformation);
264 FilePosition.CurrentByteOffset.QuadPart =
265 FileStandard.EndOfFile.QuadPart + Distance.QuadPart;
266 break;
267 case FILE_BEGIN:
268 FilePosition.CurrentByteOffset.QuadPart = Distance.QuadPart;
269 break;
270 default:
271 SetLastError(ERROR_INVALID_PARAMETER);
272 return -1;
273 }
274
275 if(FilePosition.CurrentByteOffset.QuadPart < 0)
276 {
277 SetLastError(ERROR_NEGATIVE_SEEK);
278 return -1;
279 }
280
281 errCode = NtSetInformationFile(hFile,
282 &IoStatusBlock,
283 &FilePosition,
284 sizeof(FILE_POSITION_INFORMATION),
285 FilePositionInformation);
286 if (!NT_SUCCESS(errCode))
287 {
288 SetLastErrorByStatus(errCode);
289 return -1;
290 }
291
292 if (lpDistanceToMoveHigh != NULL)
293 {
294 *lpDistanceToMoveHigh = FilePosition.CurrentByteOffset.u.HighPart;
295 }
296 return FilePosition.CurrentByteOffset.u.LowPart;
297 }
298
299
300 /*
301 * @implemented
302 */
303 BOOL
304 STDCALL
305 SetFilePointerEx(HANDLE hFile,
306 LARGE_INTEGER liDistanceToMove,
307 PLARGE_INTEGER lpNewFilePointer,
308 DWORD dwMoveMethod)
309 {
310 FILE_POSITION_INFORMATION FilePosition;
311 FILE_STANDARD_INFORMATION FileStandard;
312 NTSTATUS errCode;
313 IO_STATUS_BLOCK IoStatusBlock;
314
315 if(IsConsoleHandle(hFile))
316 {
317 SetLastError(ERROR_INVALID_HANDLE);
318 return FALSE;
319 }
320
321 switch(dwMoveMethod)
322 {
323 case FILE_CURRENT:
324 NtQueryInformationFile(hFile,
325 &IoStatusBlock,
326 &FilePosition,
327 sizeof(FILE_POSITION_INFORMATION),
328 FilePositionInformation);
329 FilePosition.CurrentByteOffset.QuadPart += liDistanceToMove.QuadPart;
330 break;
331 case FILE_END:
332 NtQueryInformationFile(hFile,
333 &IoStatusBlock,
334 &FileStandard,
335 sizeof(FILE_STANDARD_INFORMATION),
336 FileStandardInformation);
337 FilePosition.CurrentByteOffset.QuadPart =
338 FileStandard.EndOfFile.QuadPart + liDistanceToMove.QuadPart;
339 break;
340 case FILE_BEGIN:
341 FilePosition.CurrentByteOffset.QuadPart = liDistanceToMove.QuadPart;
342 break;
343 default:
344 SetLastError(ERROR_INVALID_PARAMETER);
345 return FALSE;
346 }
347
348 if(FilePosition.CurrentByteOffset.QuadPart < 0)
349 {
350 SetLastError(ERROR_NEGATIVE_SEEK);
351 return FALSE;
352 }
353
354 errCode = NtSetInformationFile(hFile,
355 &IoStatusBlock,
356 &FilePosition,
357 sizeof(FILE_POSITION_INFORMATION),
358 FilePositionInformation);
359 if (!NT_SUCCESS(errCode))
360 {
361 SetLastErrorByStatus(errCode);
362 return FALSE;
363 }
364
365 if (lpNewFilePointer)
366 {
367 *lpNewFilePointer = FilePosition.CurrentByteOffset;
368 }
369 return TRUE;
370 }
371
372
373 /*
374 * @implemented
375 */
376 DWORD STDCALL
377 GetFileType(HANDLE hFile)
378 {
379 FILE_FS_DEVICE_INFORMATION DeviceInfo;
380 IO_STATUS_BLOCK StatusBlock;
381 NTSTATUS Status;
382
383 /* Get real handle */
384 switch ((ULONG)hFile)
385 {
386 case STD_INPUT_HANDLE:
387 hFile = NtCurrentPeb()->ProcessParameters->hStdInput;
388 break;
389
390 case STD_OUTPUT_HANDLE:
391 hFile = NtCurrentPeb()->ProcessParameters->hStdOutput;
392 break;
393
394 case STD_ERROR_HANDLE:
395 hFile = NtCurrentPeb()->ProcessParameters->hStdError;
396 break;
397 }
398
399 /* Check for console handle */
400 if (IsConsoleHandle(hFile))
401 {
402 if (VerifyConsoleIoHandle(hFile))
403 return FILE_TYPE_CHAR;
404 }
405
406 Status = NtQueryVolumeInformationFile(hFile,
407 &StatusBlock,
408 &DeviceInfo,
409 sizeof(FILE_FS_DEVICE_INFORMATION),
410 FileFsDeviceInformation);
411 if (!NT_SUCCESS(Status))
412 {
413 SetLastErrorByStatus(Status);
414 return FILE_TYPE_UNKNOWN;
415 }
416
417 switch (DeviceInfo.DeviceType)
418 {
419 case FILE_DEVICE_CD_ROM:
420 case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
421 case FILE_DEVICE_CONTROLLER:
422 case FILE_DEVICE_DATALINK:
423 case FILE_DEVICE_DFS:
424 case FILE_DEVICE_DISK:
425 case FILE_DEVICE_DISK_FILE_SYSTEM:
426 case FILE_DEVICE_VIRTUAL_DISK:
427 return FILE_TYPE_DISK;
428
429 case FILE_DEVICE_KEYBOARD:
430 case FILE_DEVICE_MOUSE:
431 case FILE_DEVICE_NULL:
432 case FILE_DEVICE_PARALLEL_PORT:
433 case FILE_DEVICE_PRINTER:
434 case FILE_DEVICE_SERIAL_PORT:
435 case FILE_DEVICE_SCREEN:
436 case FILE_DEVICE_SOUND:
437 case FILE_DEVICE_MODEM:
438 return FILE_TYPE_CHAR;
439
440 case FILE_DEVICE_NAMED_PIPE:
441 return FILE_TYPE_PIPE;
442 }
443
444 return FILE_TYPE_UNKNOWN;
445 }
446
447
448 /*
449 * @implemented
450 */
451 DWORD STDCALL
452 GetFileSize(HANDLE hFile,
453 LPDWORD lpFileSizeHigh)
454 {
455 NTSTATUS errCode;
456 FILE_STANDARD_INFORMATION FileStandard;
457 IO_STATUS_BLOCK IoStatusBlock;
458
459 errCode = NtQueryInformationFile(hFile,
460 &IoStatusBlock,
461 &FileStandard,
462 sizeof(FILE_STANDARD_INFORMATION),
463 FileStandardInformation);
464 if (!NT_SUCCESS(errCode))
465 {
466 SetLastErrorByStatus(errCode);
467 if ( lpFileSizeHigh == NULL )
468 {
469 return -1;
470 }
471 else
472 {
473 return 0;
474 }
475 }
476 if ( lpFileSizeHigh != NULL )
477 *lpFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
478
479 return FileStandard.EndOfFile.u.LowPart;
480 }
481
482
483 /*
484 * @implemented
485 */
486 BOOL
487 STDCALL
488 GetFileSizeEx(
489 HANDLE hFile,
490 PLARGE_INTEGER lpFileSize
491 )
492 {
493 NTSTATUS errCode;
494 FILE_STANDARD_INFORMATION FileStandard;
495 IO_STATUS_BLOCK IoStatusBlock;
496
497 errCode = NtQueryInformationFile(hFile,
498 &IoStatusBlock,
499 &FileStandard,
500 sizeof(FILE_STANDARD_INFORMATION),
501 FileStandardInformation);
502 if (!NT_SUCCESS(errCode))
503 {
504 SetLastErrorByStatus(errCode);
505 return FALSE;
506 }
507 if (lpFileSize)
508 *lpFileSize = FileStandard.EndOfFile;
509
510 return TRUE;
511 }
512
513
514 /*
515 * @implemented
516 */
517 DWORD STDCALL
518 GetCompressedFileSizeA(LPCSTR lpFileName,
519 LPDWORD lpFileSizeHigh)
520 {
521 UNICODE_STRING FileNameU;
522 ANSI_STRING FileName;
523 DWORD Size;
524
525 RtlInitAnsiString(&FileName,
526 (LPSTR)lpFileName);
527
528 /* convert ansi (or oem) string to unicode */
529 if (bIsFileApiAnsi)
530 RtlAnsiStringToUnicodeString(&FileNameU,
531 &FileName,
532 TRUE);
533 else
534 RtlOemStringToUnicodeString(&FileNameU,
535 &FileName,
536 TRUE);
537
538 Size = GetCompressedFileSizeW(FileNameU.Buffer,
539 lpFileSizeHigh);
540
541 RtlFreeUnicodeString (&FileNameU);
542
543 return Size;
544 }
545
546
547 /*
548 * @implemented
549 */
550 DWORD STDCALL
551 GetCompressedFileSizeW(LPCWSTR lpFileName,
552 LPDWORD lpFileSizeHigh)
553 {
554 FILE_COMPRESSION_INFORMATION FileCompression;
555 NTSTATUS errCode;
556 IO_STATUS_BLOCK IoStatusBlock;
557 HANDLE hFile;
558
559 hFile = CreateFileW(lpFileName,
560 GENERIC_READ,
561 FILE_SHARE_READ,
562 NULL,
563 OPEN_EXISTING,
564 FILE_ATTRIBUTE_NORMAL,
565 NULL);
566
567 errCode = NtQueryInformationFile(hFile,
568 &IoStatusBlock,
569 &FileCompression,
570 sizeof(FILE_COMPRESSION_INFORMATION),
571 FileCompressionInformation);
572 if (!NT_SUCCESS(errCode))
573 {
574 CloseHandle(hFile);
575 SetLastErrorByStatus(errCode);
576 return INVALID_FILE_SIZE;
577 }
578 CloseHandle(hFile);
579
580 if(lpFileSizeHigh)
581 *lpFileSizeHigh = FileCompression.CompressedFileSize.u.HighPart;
582
583 return FileCompression.CompressedFileSize.u.LowPart;
584 }
585
586
587 /*
588 * @implemented
589 */
590 BOOL STDCALL
591 GetFileInformationByHandle(HANDLE hFile,
592 LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
593 {
594 struct
595 {
596 FILE_FS_VOLUME_INFORMATION FileFsVolume;
597 WCHAR Name[255];
598 }
599 FileFsVolume;
600
601 FILE_BASIC_INFORMATION FileBasic;
602 FILE_INTERNAL_INFORMATION FileInternal;
603 FILE_STANDARD_INFORMATION FileStandard;
604 NTSTATUS errCode;
605 IO_STATUS_BLOCK IoStatusBlock;
606
607 if(IsConsoleHandle(hFile))
608 {
609 SetLastError(ERROR_INVALID_HANDLE);
610 return FALSE;
611 }
612
613 errCode = NtQueryInformationFile(hFile,
614 &IoStatusBlock,
615 &FileBasic,
616 sizeof(FILE_BASIC_INFORMATION),
617 FileBasicInformation);
618 if (!NT_SUCCESS(errCode))
619 {
620 SetLastErrorByStatus(errCode);
621 return FALSE;
622 }
623
624 lpFileInformation->dwFileAttributes = (DWORD)FileBasic.FileAttributes;
625
626 lpFileInformation->ftCreationTime.dwHighDateTime = FileBasic.CreationTime.u.HighPart;
627 lpFileInformation->ftCreationTime.dwLowDateTime = FileBasic.CreationTime.u.LowPart;
628
629 lpFileInformation->ftLastAccessTime.dwHighDateTime = FileBasic.LastAccessTime.u.HighPart;
630 lpFileInformation->ftLastAccessTime.dwLowDateTime = FileBasic.LastAccessTime.u.LowPart;
631
632 lpFileInformation->ftLastWriteTime.dwHighDateTime = FileBasic.LastWriteTime.u.HighPart;
633 lpFileInformation->ftLastWriteTime.dwLowDateTime = FileBasic.LastWriteTime.u.LowPart;
634
635 errCode = NtQueryInformationFile(hFile,
636 &IoStatusBlock,
637 &FileInternal,
638 sizeof(FILE_INTERNAL_INFORMATION),
639 FileInternalInformation);
640 if (!NT_SUCCESS(errCode))
641 {
642 SetLastErrorByStatus(errCode);
643 return FALSE;
644 }
645
646 lpFileInformation->nFileIndexHigh = FileInternal.IndexNumber.u.HighPart;
647 lpFileInformation->nFileIndexLow = FileInternal.IndexNumber.u.LowPart;
648
649 errCode = NtQueryVolumeInformationFile(hFile,
650 &IoStatusBlock,
651 &FileFsVolume,
652 sizeof(FileFsVolume),
653 FileFsVolumeInformation);
654 if (!NT_SUCCESS(errCode))
655 {
656 SetLastErrorByStatus(errCode);
657 return FALSE;
658 }
659
660 lpFileInformation->dwVolumeSerialNumber = FileFsVolume.FileFsVolume.VolumeSerialNumber;
661
662 errCode = NtQueryInformationFile(hFile,
663 &IoStatusBlock,
664 &FileStandard,
665 sizeof(FILE_STANDARD_INFORMATION),
666 FileStandardInformation);
667 if (!NT_SUCCESS(errCode))
668 {
669 SetLastErrorByStatus(errCode);
670 return FALSE;
671 }
672
673 lpFileInformation->nNumberOfLinks = FileStandard.NumberOfLinks;
674 lpFileInformation->nFileSizeHigh = FileStandard.EndOfFile.u.HighPart;
675 lpFileInformation->nFileSizeLow = FileStandard.EndOfFile.u.LowPart;
676
677 return TRUE;
678 }
679
680
681 /*
682 * @implemented
683 */
684 BOOL STDCALL
685 GetFileAttributesExW(LPCWSTR lpFileName,
686 GET_FILEEX_INFO_LEVELS fInfoLevelId,
687 LPVOID lpFileInformation)
688 {
689 FILE_NETWORK_OPEN_INFORMATION FileInformation;
690 OBJECT_ATTRIBUTES ObjectAttributes;
691 IO_STATUS_BLOCK IoStatusBlock;
692 UNICODE_STRING FileName;
693 HANDLE FileHandle;
694 NTSTATUS Status;
695 WIN32_FILE_ATTRIBUTE_DATA* FileAttributeData;
696
697 DPRINT ("GetFileAttributesExW(%S) called\n", lpFileName);
698
699
700 if (fInfoLevelId != GetFileExInfoStandard || lpFileInformation == NULL)
701 {
702 SetLastError(ERROR_INVALID_PARAMETER);
703 return FALSE;
704 }
705
706 /* Validate and translate the filename */
707 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
708 &FileName,
709 NULL,
710 NULL))
711 {
712 DPRINT ("Invalid path\n");
713 SetLastError (ERROR_BAD_PATHNAME);
714 return FALSE;
715 }
716
717 /* build the object attributes */
718 InitializeObjectAttributes (&ObjectAttributes,
719 &FileName,
720 OBJ_CASE_INSENSITIVE,
721 NULL,
722 NULL);
723
724 /* Open the file */
725 Status = NtOpenFile (&FileHandle,
726 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
727 &ObjectAttributes,
728 &IoStatusBlock,
729 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
730 FILE_SYNCHRONOUS_IO_NONALERT);
731 RtlFreeUnicodeString (&FileName);
732 if (!NT_SUCCESS (Status))
733 {
734 DPRINT ("NtOpenFile() failed (Status %lx)\n", Status);
735 SetLastErrorByStatus (Status);
736 return FALSE;
737 }
738
739 /* Get file attributes */
740 Status = NtQueryInformationFile (FileHandle,
741 &IoStatusBlock,
742 &FileInformation,
743 sizeof(FILE_NETWORK_OPEN_INFORMATION),
744 FileNetworkOpenInformation);
745 NtClose (FileHandle);
746
747 if (!NT_SUCCESS (Status))
748 {
749 DPRINT ("NtQueryInformationFile() failed (Status %lx)\n", Status);
750 SetLastErrorByStatus (Status);
751 return FALSE;
752 }
753
754 FileAttributeData = (WIN32_FILE_ATTRIBUTE_DATA*)lpFileInformation;
755 FileAttributeData->dwFileAttributes = FileInformation.FileAttributes;
756 FileAttributeData->ftCreationTime.dwLowDateTime = FileInformation.CreationTime.u.LowPart;
757 FileAttributeData->ftCreationTime.dwHighDateTime = FileInformation.CreationTime.u.HighPart;
758 FileAttributeData->ftLastAccessTime.dwLowDateTime = FileInformation.LastAccessTime.u.LowPart;
759 FileAttributeData->ftLastAccessTime.dwHighDateTime = FileInformation.LastAccessTime.u.HighPart;
760 FileAttributeData->ftLastWriteTime.dwLowDateTime = FileInformation.LastWriteTime.u.LowPart;
761 FileAttributeData->ftLastWriteTime.dwHighDateTime = FileInformation.LastWriteTime.u.HighPart;
762 FileAttributeData->nFileSizeLow = FileInformation.EndOfFile.u.LowPart;
763 FileAttributeData->nFileSizeHigh = FileInformation.EndOfFile.u.HighPart;
764
765 return TRUE;
766 }
767
768 /*
769 * @implemented
770 */
771 BOOL STDCALL
772 GetFileAttributesExA(LPCSTR lpFileName,
773 GET_FILEEX_INFO_LEVELS fInfoLevelId,
774 LPVOID lpFileInformation)
775 {
776 UNICODE_STRING FileNameU;
777 ANSI_STRING FileName;
778 BOOL Result;
779 RtlInitAnsiString (&FileName,
780 (LPSTR)lpFileName);
781
782 /* convert ansi (or oem) string to unicode */
783 if (bIsFileApiAnsi)
784 RtlAnsiStringToUnicodeString (&FileNameU,
785 &FileName,
786 TRUE);
787 else
788 RtlOemStringToUnicodeString (&FileNameU,
789 &FileName,
790 TRUE);
791
792 Result = GetFileAttributesExW(FileNameU.Buffer, fInfoLevelId, lpFileInformation);
793
794 RtlFreeUnicodeString (&FileNameU);
795
796 return Result;
797 }
798
799
800 /*
801 * @implemented
802 */
803 DWORD STDCALL
804 GetFileAttributesA(LPCSTR lpFileName)
805 {
806 WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
807 UNICODE_STRING FileNameU;
808 ANSI_STRING FileName;
809 BOOL Result;
810
811 RtlInitAnsiString (&FileName,
812 (LPSTR)lpFileName);
813
814 /* convert ansi (or oem) string to unicode */
815 if (bIsFileApiAnsi)
816 RtlAnsiStringToUnicodeString (&FileNameU,
817 &FileName,
818 TRUE);
819 else
820 RtlOemStringToUnicodeString (&FileNameU,
821 &FileName,
822 TRUE);
823
824 Result = GetFileAttributesExW(FileNameU.Buffer, GetFileExInfoStandard, &FileAttributeData);
825
826 RtlFreeUnicodeString (&FileNameU);
827
828 return Result ? FileAttributeData.dwFileAttributes : 0xffffffff;
829 }
830
831
832 /*
833 * @implemented
834 */
835 DWORD STDCALL
836 GetFileAttributesW(LPCWSTR lpFileName)
837 {
838 WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
839 BOOL Result;
840
841 DPRINT ("GetFileAttributeW(%S) called\n", lpFileName);
842
843 Result = GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &FileAttributeData);
844
845 return Result ? FileAttributeData.dwFileAttributes : 0xffffffff;
846 }
847
848 BOOL STDCALL
849 SetFileAttributesA(LPCSTR lpFileName,
850 DWORD dwFileAttributes)
851 {
852 UNICODE_STRING FileNameU;
853 ANSI_STRING FileName;
854 BOOL Result;
855
856 RtlInitAnsiString (&FileName,
857 (LPSTR)lpFileName);
858
859 /* convert ansi (or oem) string to unicode */
860 if (bIsFileApiAnsi)
861 RtlAnsiStringToUnicodeString (&FileNameU,
862 &FileName,
863 TRUE);
864 else
865 RtlOemStringToUnicodeString (&FileNameU,
866 &FileName,
867 TRUE);
868
869 Result = SetFileAttributesW (FileNameU.Buffer,
870 dwFileAttributes);
871
872 RtlFreeUnicodeString (&FileNameU);
873
874 return Result;
875 }
876
877
878 /*
879 * @implemented
880 */
881 BOOL STDCALL
882 SetFileAttributesW(LPCWSTR lpFileName,
883 DWORD dwFileAttributes)
884 {
885 FILE_BASIC_INFORMATION FileInformation;
886 OBJECT_ATTRIBUTES ObjectAttributes;
887 IO_STATUS_BLOCK IoStatusBlock;
888 UNICODE_STRING FileName;
889 HANDLE FileHandle;
890 NTSTATUS Status;
891
892 DPRINT ("SetFileAttributeW(%S, 0x%lx) called\n", lpFileName, dwFileAttributes);
893
894 /* Validate and translate the filename */
895 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
896 &FileName,
897 NULL,
898 NULL))
899 {
900 DPRINT ("Invalid path\n");
901 SetLastError (ERROR_BAD_PATHNAME);
902 return FALSE;
903 }
904 DPRINT ("FileName: \'%wZ\'\n", &FileName);
905
906 /* build the object attributes */
907 InitializeObjectAttributes (&ObjectAttributes,
908 &FileName,
909 OBJ_CASE_INSENSITIVE,
910 NULL,
911 NULL);
912
913 /* Open the file */
914 Status = NtOpenFile (&FileHandle,
915 SYNCHRONIZE | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES,
916 &ObjectAttributes,
917 &IoStatusBlock,
918 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
919 FILE_SYNCHRONOUS_IO_NONALERT);
920 RtlFreeUnicodeString (&FileName);
921 if (!NT_SUCCESS (Status))
922 {
923 DPRINT ("NtOpenFile() failed (Status %lx)\n", Status);
924 SetLastErrorByStatus (Status);
925 return FALSE;
926 }
927
928 Status = NtQueryInformationFile(FileHandle,
929 &IoStatusBlock,
930 &FileInformation,
931 sizeof(FILE_BASIC_INFORMATION),
932 FileBasicInformation);
933 if (!NT_SUCCESS(Status))
934 {
935 DPRINT ("SetFileAttributes NtQueryInformationFile failed with status 0x%08x\n", Status);
936 NtClose (FileHandle);
937 SetLastErrorByStatus (Status);
938 return FALSE;
939 }
940
941 FileInformation.FileAttributes = dwFileAttributes;
942 Status = NtSetInformationFile(FileHandle,
943 &IoStatusBlock,
944 &FileInformation,
945 sizeof(FILE_BASIC_INFORMATION),
946 FileBasicInformation);
947 NtClose (FileHandle);
948 if (!NT_SUCCESS(Status))
949 {
950 DPRINT ("SetFileAttributes NtSetInformationFile failed with status 0x%08x\n", Status);
951 SetLastErrorByStatus (Status);
952 return FALSE;
953 }
954
955 return TRUE;
956 }
957
958
959 /*
960 * @implemented
961 */
962 UINT STDCALL
963 GetTempFileNameA(LPCSTR lpPathName,
964 LPCSTR lpPrefixString,
965 UINT uUnique,
966 LPSTR lpTempFileName)
967 {
968 HANDLE hFile;
969 UINT unique = uUnique;
970 UINT len;
971 const char *format = "%.*s\\~%.3s%4.4x.TMP";
972
973 DPRINT("GetTempFileNameA(lpPathName %s, lpPrefixString %.*s, "
974 "uUnique %x, lpTempFileName %x)\n", lpPathName, 4,
975 lpPrefixString, uUnique, lpTempFileName);
976
977 if (lpPathName == NULL)
978 return 0;
979
980 len = strlen(lpPathName);
981 if (len > 0 && (lpPathName[len-1] == '\\' || lpPathName[len-1] == '/'))
982 len--;
983
984 if (uUnique == 0)
985 uUnique = GetCurrentTime();
986
987 sprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,uUnique);
988
989 if (unique)
990 return uUnique;
991
992 while ((hFile = CreateFileA(lpTempFileName, GENERIC_WRITE, 0, NULL,
993 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
994 0)) == INVALID_HANDLE_VALUE)
995 {
996 if (GetLastError() != ERROR_FILE_EXISTS)
997 {
998 return 0;
999 }
1000 sprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,++uUnique);
1001 }
1002 CloseHandle(hFile);
1003 return uUnique;
1004 }
1005
1006
1007 /*
1008 * @implemented
1009 */
1010 UINT STDCALL
1011 GetTempFileNameW(LPCWSTR lpPathName,
1012 LPCWSTR lpPrefixString,
1013 UINT uUnique,
1014 LPWSTR lpTempFileName)
1015 {
1016 HANDLE hFile;
1017 UINT unique = uUnique;
1018 UINT len;
1019 const WCHAR *format = L"%.*s\\~%.3s%4.4x.TMP";
1020
1021 DPRINT("GetTempFileNameW(lpPathName %S, lpPrefixString %.*S, "
1022 "uUnique %x, lpTempFileName %x)\n", lpPathName, 4,
1023 lpPrefixString, uUnique, lpTempFileName);
1024
1025 if (lpPathName == NULL)
1026 return 0;
1027
1028 len = wcslen(lpPathName);
1029 if (len > 0 && (lpPathName[len-1] == L'\\' || lpPathName[len-1] == L'/'))
1030 len--;
1031
1032 if (uUnique == 0)
1033 uUnique = GetCurrentTime();
1034
1035 swprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,uUnique);
1036
1037 if (unique)
1038 return uUnique;
1039
1040 while ((hFile = CreateFileW(lpTempFileName, GENERIC_WRITE, 0, NULL,
1041 CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY,
1042 0)) == INVALID_HANDLE_VALUE)
1043 {
1044 if (GetLastError() != ERROR_FILE_EXISTS)
1045 {
1046 return 0;
1047 }
1048 swprintf(lpTempFileName,format,len,lpPathName,lpPrefixString,++uUnique);
1049 }
1050 CloseHandle(hFile);
1051 return uUnique;
1052 }
1053
1054
1055 /*
1056 * @implemented
1057 */
1058 BOOL STDCALL
1059 GetFileTime(HANDLE hFile,
1060 LPFILETIME lpCreationTime,
1061 LPFILETIME lpLastAccessTime,
1062 LPFILETIME lpLastWriteTime)
1063 {
1064 IO_STATUS_BLOCK IoStatusBlock;
1065 FILE_BASIC_INFORMATION FileBasic;
1066 NTSTATUS Status;
1067
1068 if(IsConsoleHandle(hFile))
1069 {
1070 SetLastError(ERROR_INVALID_HANDLE);
1071 return FALSE;
1072 }
1073
1074 Status = NtQueryInformationFile(hFile,
1075 &IoStatusBlock,
1076 &FileBasic,
1077 sizeof(FILE_BASIC_INFORMATION),
1078 FileBasicInformation);
1079 if (!NT_SUCCESS(Status))
1080 {
1081 SetLastErrorByStatus(Status);
1082 return FALSE;
1083 }
1084
1085 if (lpCreationTime)
1086 memcpy(lpCreationTime, &FileBasic.CreationTime, sizeof(FILETIME));
1087 if (lpLastAccessTime)
1088 memcpy(lpLastAccessTime, &FileBasic.LastAccessTime, sizeof(FILETIME));
1089 if (lpLastWriteTime)
1090 memcpy(lpLastWriteTime, &FileBasic.LastWriteTime, sizeof(FILETIME));
1091
1092 return TRUE;
1093 }
1094
1095
1096 /*
1097 * @implemented
1098 */
1099 BOOL STDCALL
1100 SetFileTime(HANDLE hFile,
1101 CONST FILETIME *lpCreationTime,
1102 CONST FILETIME *lpLastAccessTime,
1103 CONST FILETIME *lpLastWriteTime)
1104 {
1105 FILE_BASIC_INFORMATION FileBasic;
1106 IO_STATUS_BLOCK IoStatusBlock;
1107 NTSTATUS Status;
1108
1109 if(IsConsoleHandle(hFile))
1110 {
1111 SetLastError(ERROR_INVALID_HANDLE);
1112 return FALSE;
1113 }
1114
1115 Status = NtQueryInformationFile(hFile,
1116 &IoStatusBlock,
1117 &FileBasic,
1118 sizeof(FILE_BASIC_INFORMATION),
1119 FileBasicInformation);
1120 if (!NT_SUCCESS(Status))
1121 {
1122 SetLastErrorByStatus(Status);
1123 return FALSE;
1124 }
1125
1126 if (lpCreationTime)
1127 memcpy(&FileBasic.CreationTime, lpCreationTime, sizeof(FILETIME));
1128 if (lpLastAccessTime)
1129 memcpy(&FileBasic.LastAccessTime, lpLastAccessTime, sizeof(FILETIME));
1130 if (lpLastWriteTime)
1131 memcpy(&FileBasic.LastWriteTime, lpLastWriteTime, sizeof(FILETIME));
1132
1133 // should i initialize changetime ???
1134
1135 Status = NtSetInformationFile(hFile,
1136 &IoStatusBlock,
1137 &FileBasic,
1138 sizeof(FILE_BASIC_INFORMATION),
1139 FileBasicInformation);
1140 if (!NT_SUCCESS(Status))
1141 {
1142 SetLastErrorByStatus(Status);
1143 return FALSE;
1144 }
1145
1146 return TRUE;
1147 }
1148
1149
1150 /*
1151 * The caller must have opened the file with the DesiredAccess FILE_WRITE_DATA flag set.
1152 *
1153 * @implemented
1154 */
1155 BOOL STDCALL
1156 SetEndOfFile(HANDLE hFile)
1157 {
1158 IO_STATUS_BLOCK IoStatusBlock;
1159 FILE_END_OF_FILE_INFORMATION EndOfFileInfo;
1160 FILE_ALLOCATION_INFORMATION FileAllocationInfo;
1161 FILE_POSITION_INFORMATION FilePosInfo;
1162 NTSTATUS Status;
1163
1164 if(IsConsoleHandle(hFile))
1165 {
1166 SetLastError(ERROR_INVALID_HANDLE);
1167 return FALSE;
1168 }
1169
1170 //get current position
1171 Status = NtQueryInformationFile(
1172 hFile,
1173 &IoStatusBlock,
1174 &FilePosInfo,
1175 sizeof(FILE_POSITION_INFORMATION),
1176 FilePositionInformation
1177 );
1178
1179 if (!NT_SUCCESS(Status)){
1180 SetLastErrorByStatus(Status);
1181 return FALSE;
1182 }
1183
1184 EndOfFileInfo.EndOfFile.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1185
1186 /*
1187 NOTE:
1188 This call is not supposed to free up any space after the eof marker
1189 if the file gets truncated. We have to deallocate the space explicitly afterwards.
1190 But...most file systems dispatch both FileEndOfFileInformation
1191 and FileAllocationInformation as they were the same command.
1192
1193 */
1194 Status = NtSetInformationFile(
1195 hFile,
1196 &IoStatusBlock, //out
1197 &EndOfFileInfo,
1198 sizeof(FILE_END_OF_FILE_INFORMATION),
1199 FileEndOfFileInformation
1200 );
1201
1202 if (!NT_SUCCESS(Status)){
1203 SetLastErrorByStatus(Status);
1204 return FALSE;
1205 }
1206
1207 FileAllocationInfo.AllocationSize.QuadPart = FilePosInfo.CurrentByteOffset.QuadPart;
1208
1209
1210 Status = NtSetInformationFile(
1211 hFile,
1212 &IoStatusBlock, //out
1213 &FileAllocationInfo,
1214 sizeof(FILE_ALLOCATION_INFORMATION),
1215 FileAllocationInformation
1216 );
1217
1218 if (!NT_SUCCESS(Status)){
1219 SetLastErrorByStatus(Status);
1220 return FALSE;
1221 }
1222
1223 return TRUE;
1224
1225 }
1226
1227
1228 /*
1229 * @implemented
1230 */
1231 BOOL
1232 STDCALL
1233 SetFileValidData(
1234 HANDLE hFile,
1235 LONGLONG ValidDataLength
1236 )
1237 {
1238 IO_STATUS_BLOCK IoStatusBlock;
1239 FILE_VALID_DATA_LENGTH_INFORMATION ValidDataLengthInformation;
1240 NTSTATUS Status;
1241
1242 ValidDataLengthInformation.ValidDataLength.QuadPart = ValidDataLength;
1243
1244 Status = NtSetInformationFile(
1245 hFile,
1246 &IoStatusBlock, //out
1247 &ValidDataLengthInformation,
1248 sizeof(FILE_VALID_DATA_LENGTH_INFORMATION),
1249 FileValidDataLengthInformation
1250 );
1251
1252 if (!NT_SUCCESS(Status)){
1253 SetLastErrorByStatus(Status);
1254 return FALSE;
1255 }
1256
1257 return TRUE;
1258 }
1259
1260
1261 /*
1262 * @implemented
1263 */
1264 BOOL
1265 STDCALL
1266 SetFileShortNameW(
1267 HANDLE hFile,
1268 LPCWSTR lpShortName)
1269 {
1270 NTSTATUS Status;
1271 ULONG NeededSize;
1272 UNICODE_STRING ShortName;
1273 IO_STATUS_BLOCK IoStatusBlock;
1274 PFILE_NAME_INFORMATION FileNameInformation;
1275
1276 if(IsConsoleHandle(hFile))
1277 {
1278 SetLastError(ERROR_INVALID_HANDLE);
1279 return FALSE;
1280 }
1281
1282 if(!lpShortName)
1283 {
1284 SetLastError(ERROR_INVALID_PARAMETER);
1285 return FALSE;
1286 }
1287
1288 RtlInitUnicodeString(&ShortName, lpShortName);
1289
1290 NeededSize = sizeof(FILE_NAME_INFORMATION) + ShortName.Length + sizeof(WCHAR);
1291 if(!(FileNameInformation = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, NeededSize)))
1292 {
1293 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1294 return FALSE;
1295 }
1296
1297 FileNameInformation->FileNameLength = ShortName.Length;
1298 RtlCopyMemory(FileNameInformation->FileName, ShortName.Buffer, ShortName.Length);
1299
1300 Status = NtSetInformationFile(hFile,
1301 &IoStatusBlock, //out
1302 FileNameInformation,
1303 NeededSize,
1304 FileShortNameInformation);
1305
1306 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameInformation);
1307 if(!NT_SUCCESS(Status))
1308 {
1309
1310 SetLastErrorByStatus(Status);
1311 }
1312
1313 return NT_SUCCESS(Status);
1314 }
1315
1316
1317 /*
1318 * @implemented
1319 */
1320 BOOL
1321 STDCALL
1322 SetFileShortNameA(
1323 HANDLE hFile,
1324 LPCSTR lpShortName
1325 )
1326 {
1327 NTSTATUS Status;
1328 BOOL Ret;
1329 ANSI_STRING ShortNameA;
1330 UNICODE_STRING ShortName;
1331
1332 if(IsConsoleHandle(hFile))
1333 {
1334 SetLastError(ERROR_INVALID_HANDLE);
1335 return FALSE;
1336 }
1337
1338 if(!lpShortName)
1339 {
1340 SetLastError(ERROR_INVALID_PARAMETER);
1341 return FALSE;
1342 }
1343
1344 RtlInitAnsiString(&ShortNameA, (LPSTR)lpShortName);
1345
1346 if(bIsFileApiAnsi)
1347 Status = RtlAnsiStringToUnicodeString(&ShortName, &ShortNameA, TRUE);
1348 else
1349 Status = RtlOemStringToUnicodeString(&ShortName, &ShortNameA, TRUE);
1350 if(!NT_SUCCESS(Status))
1351 {
1352 SetLastErrorByStatus(Status);
1353 return FALSE;
1354 }
1355
1356 Ret = SetFileShortNameW(hFile, ShortName.Buffer);
1357
1358 RtlFreeUnicodeString(&ShortName);
1359 return Ret;
1360 }
1361
1362
1363 /*
1364 * @implemented
1365 */
1366 BOOL
1367 STDCALL
1368 CheckNameLegalDOS8Dot3W(
1369 LPCWSTR lpName,
1370 LPSTR lpOemName OPTIONAL,
1371 DWORD OemNameSize OPTIONAL,
1372 PBOOL pbNameContainsSpaces OPTIONAL,
1373 PBOOL pbNameLegal
1374 )
1375 {
1376 UNICODE_STRING Name;
1377 ANSI_STRING AnsiName;
1378
1379 if(lpName == NULL ||
1380 (lpOemName == NULL && OemNameSize != 0) ||
1381 pbNameLegal == NULL)
1382 {
1383 SetLastError(ERROR_INVALID_PARAMETER);
1384 return FALSE;
1385 }
1386
1387 if(lpOemName != NULL)
1388 {
1389 AnsiName.Buffer = lpOemName;
1390 AnsiName.MaximumLength = OemNameSize * sizeof(CHAR);
1391 AnsiName.Length = 0;
1392 }
1393
1394 RtlInitUnicodeString(&Name, lpName);
1395
1396 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1397 (lpOemName ? &AnsiName : NULL),
1398 (BOOLEAN*)pbNameContainsSpaces);
1399
1400 return TRUE;
1401 }
1402
1403
1404 /*
1405 * @implemented
1406 */
1407 BOOL
1408 STDCALL
1409 CheckNameLegalDOS8Dot3A(
1410 LPCSTR lpName,
1411 LPSTR lpOemName OPTIONAL,
1412 DWORD OemNameSize OPTIONAL,
1413 PBOOL pbNameContainsSpaces OPTIONAL,
1414 PBOOL pbNameLegal
1415 )
1416 {
1417 UNICODE_STRING Name;
1418 ANSI_STRING AnsiName, AnsiInputName;
1419 NTSTATUS Status;
1420
1421 if(lpName == NULL ||
1422 (lpOemName == NULL && OemNameSize != 0) ||
1423 pbNameLegal == NULL)
1424 {
1425 SetLastError(ERROR_INVALID_PARAMETER);
1426 return FALSE;
1427 }
1428
1429 if(lpOemName != NULL)
1430 {
1431 AnsiName.Buffer = lpOemName;
1432 AnsiName.MaximumLength = OemNameSize * sizeof(CHAR);
1433 AnsiName.Length = 0;
1434 }
1435
1436 RtlInitAnsiString(&AnsiInputName, (LPSTR)lpName);
1437 if(bIsFileApiAnsi)
1438 Status = RtlAnsiStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1439 else
1440 Status = RtlOemStringToUnicodeString(&Name, &AnsiInputName, TRUE);
1441
1442 if(!NT_SUCCESS(Status))
1443 {
1444 SetLastErrorByStatus(Status);
1445 return FALSE;
1446 }
1447
1448 *pbNameLegal = RtlIsNameLegalDOS8Dot3(&Name,
1449 (lpOemName ? &AnsiName : NULL),
1450 (BOOLEAN*)pbNameContainsSpaces);
1451
1452 RtlFreeUnicodeString(&Name);
1453
1454 return TRUE;
1455 }
1456
1457 /* EOF */