3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/file/create.c
6 * PURPOSE: Directory functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
10 * Removed use of SearchPath (not used by Windows)
11 * 18/08/2002: CreateFileW mess cleaned up (KJK::Hyperion)
12 * 24/08/2002: removed superfluous DPRINTs (KJK::Hyperion)
15 /* INCLUDES *****************************************************************/
17 /* File contains Vista Semantics */
19 #define _WIN32_WINNT 0x0600
24 #include "../include/debug.h"
27 /* FUNCTIONS ****************************************************************/
32 HANDLE STDCALL
CreateFileA (LPCSTR lpFileName
,
33 DWORD dwDesiredAccess
,
35 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
36 DWORD dwCreationDisposition
,
37 DWORD dwFlagsAndAttributes
,
43 DPRINT("CreateFileA(lpFileName %s)\n",lpFileName
);
45 if (!(FileNameW
= FilenameA2W(lpFileName
, FALSE
)))
46 return INVALID_HANDLE_VALUE
;
48 FileHandle
= CreateFileW (FileNameW
,
52 dwCreationDisposition
,
63 HANDLE STDCALL
CreateFileW (LPCWSTR lpFileName
,
64 DWORD dwDesiredAccess
,
66 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
67 DWORD dwCreationDisposition
,
68 DWORD dwFlagsAndAttributes
,
71 OBJECT_ATTRIBUTES ObjectAttributes
;
72 IO_STATUS_BLOCK IoStatusBlock
;
73 UNICODE_STRING NtPathU
;
76 ULONG FileAttributes
, Flags
= 0;
77 CSR_API_MESSAGE Request
;
78 PVOID EaBuffer
= NULL
;
81 DPRINT("CreateFileW(lpFileName %S)\n",lpFileName
);
83 /* validate & translate the creation disposition */
84 switch (dwCreationDisposition
)
87 dwCreationDisposition
= FILE_CREATE
;
91 dwCreationDisposition
= FILE_OVERWRITE_IF
;
95 dwCreationDisposition
= FILE_OPEN
;
99 dwCreationDisposition
= FILE_OPEN_IF
;
102 case TRUNCATE_EXISTING
:
103 dwCreationDisposition
= FILE_OVERWRITE
;
107 SetLastError(ERROR_INVALID_PARAMETER
);
108 return (INVALID_HANDLE_VALUE
);
111 /* validate & translate the flags */
113 /* translate the flags that need no validation */
114 if (!(dwFlagsAndAttributes
& FILE_FLAG_OVERLAPPED
))
116 /* yes, nonalert is correct! apc's are not delivered
117 while waiting for file io to complete */
118 Flags
|= FILE_SYNCHRONOUS_IO_NONALERT
;
121 if(dwFlagsAndAttributes
& FILE_FLAG_WRITE_THROUGH
)
122 Flags
|= FILE_WRITE_THROUGH
;
124 if(dwFlagsAndAttributes
& FILE_FLAG_NO_BUFFERING
)
125 Flags
|= FILE_NO_INTERMEDIATE_BUFFERING
;
127 if(dwFlagsAndAttributes
& FILE_FLAG_RANDOM_ACCESS
)
128 Flags
|= FILE_RANDOM_ACCESS
;
130 if(dwFlagsAndAttributes
& FILE_FLAG_SEQUENTIAL_SCAN
)
131 Flags
|= FILE_SEQUENTIAL_ONLY
;
133 if(dwFlagsAndAttributes
& FILE_FLAG_DELETE_ON_CLOSE
)
134 Flags
|= FILE_DELETE_ON_CLOSE
;
136 if(dwFlagsAndAttributes
& FILE_FLAG_BACKUP_SEMANTICS
)
138 if(dwDesiredAccess
& GENERIC_ALL
)
139 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_FOR_RECOVERY
;
142 if(dwDesiredAccess
& GENERIC_READ
)
143 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
;
145 if(dwDesiredAccess
& GENERIC_WRITE
)
146 Flags
|= FILE_OPEN_FOR_RECOVERY
;
150 Flags
|= FILE_NON_DIRECTORY_FILE
;
152 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_REPARSE_POINT
)
153 Flags
|= FILE_OPEN_REPARSE_POINT
;
155 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_NO_RECALL
)
156 Flags
|= FILE_OPEN_NO_RECALL
;
158 FileAttributes
= (dwFlagsAndAttributes
& (FILE_ATTRIBUTE_VALID_FLAGS
& ~FILE_ATTRIBUTE_DIRECTORY
));
160 /* handle may allways be waited on and querying attributes are allways allowed */
161 dwDesiredAccess
|= SYNCHRONIZE
| FILE_READ_ATTRIBUTES
;
163 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
165 /* check for console output */
166 if (0 == _wcsicmp(L
"CONOUT$", lpFileName
))
168 /* FIXME: Send required access rights to Csrss */
169 Status
= CsrClientCallServer(&Request
,
171 MAKE_CSR_API(GET_OUTPUT_HANDLE
, CSR_NATIVE
),
172 sizeof(CSR_API_MESSAGE
));
173 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(Status
= Request
.Status
))
175 SetLastErrorByStatus(Status
);
176 return INVALID_HANDLE_VALUE
;
180 return Request
.Data
.GetOutputHandleRequest
.OutputHandle
;
184 /* check for console input */
185 if (0 == _wcsicmp(L
"CONIN$", lpFileName
))
187 /* FIXME: Send required access rights to Csrss */
188 Status
= CsrClientCallServer(&Request
,
190 MAKE_CSR_API(GET_INPUT_HANDLE
, CSR_NATIVE
),
191 sizeof(CSR_API_MESSAGE
));
192 if (!NT_SUCCESS(Status
) || !NT_SUCCESS(Status
= Request
.Status
))
194 SetLastErrorByStatus(Status
);
195 return INVALID_HANDLE_VALUE
;
199 return Request
.Data
.GetInputHandleRequest
.InputHandle
;
203 /* validate & translate the filename */
204 if (!RtlDosPathNameToNtPathName_U (lpFileName
,
209 DPRINT("Invalid path\n");
210 SetLastError(ERROR_PATH_NOT_FOUND
);
211 return INVALID_HANDLE_VALUE
;
214 DPRINT("NtPathU \'%wZ\'\n", &NtPathU
);
216 if (hTemplateFile
!= NULL
)
218 FILE_EA_INFORMATION EaInformation
;
222 /* try to get the size of the extended attributes, if we fail just continue
223 creating the file without copying the attributes! */
224 Status
= NtQueryInformationFile(hTemplateFile
,
227 sizeof(FILE_EA_INFORMATION
),
229 if (NT_SUCCESS(Status
) && (EaInformation
.EaSize
!= 0))
231 /* there's extended attributes to read, let's give it a try */
232 EaBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
234 EaInformation
.EaSize
);
235 if (EaBuffer
== NULL
)
237 RtlFreeHeap(RtlGetProcessHeap(),
241 /* the template file handle is valid and has extended attributes,
242 however we seem to lack some memory here. We should fail here! */
243 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
244 return INVALID_HANDLE_VALUE
;
247 Status
= NtQueryEaFile(hTemplateFile
,
250 EaInformation
.EaSize
,
257 if (NT_SUCCESS(Status
))
259 /* we successfully read the extended attributes, break the loop
261 EaLength
= EaInformation
.EaSize
;
266 RtlFreeHeap(RtlGetProcessHeap(),
271 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
273 /* unless we just allocated not enough memory, break the loop
274 and just continue without copying extended attributes */
281 /* we either failed to get the size of the extended attributes or
282 they're empty, just continue as there's no need to copy
289 /* build the object attributes */
290 InitializeObjectAttributes(&ObjectAttributes
,
296 if (lpSecurityAttributes
)
298 if(lpSecurityAttributes
->bInheritHandle
)
299 ObjectAttributes
.Attributes
|= OBJ_INHERIT
;
301 ObjectAttributes
.SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
304 if(!(dwFlagsAndAttributes
& FILE_FLAG_POSIX_SEMANTICS
))
305 ObjectAttributes
.Attributes
|= OBJ_CASE_INSENSITIVE
;
307 /* perform the call */
308 Status
= NtCreateFile (&FileHandle
,
315 dwCreationDisposition
,
320 RtlFreeHeap(RtlGetProcessHeap(),
324 /* free the extended attributes buffer if allocated */
325 if (EaBuffer
!= NULL
)
327 RtlFreeHeap(RtlGetProcessHeap(),
333 if (!NT_SUCCESS(Status
))
335 /* In the case file creation was rejected due to CREATE_NEW flag
336 * was specified and file with that name already exists, correct
337 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
338 * Note: RtlNtStatusToDosError is not the subject to blame here.
340 if (Status
== STATUS_OBJECT_NAME_COLLISION
&&
341 dwCreationDisposition
== FILE_CREATE
)
343 SetLastError( ERROR_FILE_EXISTS
);
347 SetLastErrorByStatus (Status
);
350 return INVALID_HANDLE_VALUE
;
354 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
355 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
357 if (dwCreationDisposition
== FILE_OPEN_IF
)
359 SetLastError(IoStatusBlock
.Information
== FILE_OPENED
? ERROR_ALREADY_EXISTS
: 0);
361 else if (dwCreationDisposition
== FILE_OVERWRITE_IF
)
363 SetLastError(IoStatusBlock
.Information
== FILE_OVERWRITTEN
? ERROR_ALREADY_EXISTS
: 0);
374 CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName
,
375 IN LPCWSTR lpTargetFileName
,
378 IO_STATUS_BLOCK IoStatusBlock
;
379 OBJECT_ATTRIBUTES ObjectAttributes
;
380 HANDLE hSymlink
= NULL
;
381 UNICODE_STRING SymlinkFileName
= { 0, 0, NULL
};
382 UNICODE_STRING TargetFileName
= { 0, 0, NULL
};
383 BOOLEAN bAllocatedTarget
= FALSE
, bRelativePath
= FALSE
;
384 LPWSTR lpTargetFullFileName
= NULL
;
386 SIZE_T cbReparseData
;
387 PREPARSE_DATA_BUFFER pReparseData
= NULL
;
390 ULONG dwCreateOptions
;
393 if(!lpSymlinkFileName
|| !lpTargetFileName
|| (dwFlags
| SYMLINK_FLAG_DIRECTORY
) != SYMLINK_FLAG_DIRECTORY
)
395 SetLastError(ERROR_INVALID_PARAMETER
);
399 if(dwFlags
& SYMLINK_FLAG_DIRECTORY
)
400 dwCreateOptions
= FILE_DIRECTORY_FILE
;
402 dwCreateOptions
= FILE_NON_DIRECTORY_FILE
;
404 switch(RtlDetermineDosPathNameType_U(lpTargetFileName
))
406 case RtlPathTypeUnknown
:
407 case RtlPathTypeRooted
:
408 case RtlPathTypeRelative
:
409 bRelativePath
= TRUE
;
410 RtlInitUnicodeString(&TargetFileName
, lpTargetFileName
);
413 case RtlPathTypeDriveRelative
:
416 SIZE_T cchTargetFullFileName
;
418 cchTargetFullFileName
= GetFullPathNameW(lpTargetFileName
, 0, NULL
, &FilePart
);
420 if(cchTargetFullFileName
== 0)
422 dwErr
= GetLastError();
426 lpTargetFullFileName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName
* sizeof(WCHAR
));
428 if(lpTargetFullFileName
== NULL
)
430 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
434 if(GetFullPathNameW(lpTargetFileName
, cchTargetFullFileName
, lpTargetFullFileName
, &FilePart
) == 0)
436 dwErr
= GetLastError();
441 lpTargetFileName
= lpTargetFullFileName
;
445 case RtlPathTypeUncAbsolute
:
446 case RtlPathTypeDriveAbsolute
:
447 case RtlPathTypeLocalDevice
:
448 case RtlPathTypeRootLocalDevice
:
450 if(!RtlDosPathNameToNtPathName_U(lpTargetFileName
, &TargetFileName
, NULL
, NULL
))
452 bAllocatedTarget
= TRUE
;
453 dwErr
= ERROR_INVALID_PARAMETER
;
458 cbPrintName
= wcslen(lpTargetFileName
) * sizeof(WCHAR
);
459 cbReparseData
= FIELD_OFFSET(REPARSE_DATA_BUFFER
, SymbolicLinkReparseBuffer
.PathBuffer
) + TargetFileName
.Length
+ cbPrintName
;
460 pReparseData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData
);
462 if(pReparseData
== NULL
)
464 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
468 pBufTail
= (PBYTE
)(pReparseData
->SymbolicLinkReparseBuffer
.PathBuffer
);
470 pReparseData
->ReparseTag
= IO_REPARSE_TAG_SYMLINK
;
471 pReparseData
->ReparseDataLength
= cbReparseData
- REPARSE_DATA_BUFFER_HEADER_SIZE
;
472 pReparseData
->Reserved
= 0;
474 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
= 0;
475 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
= TargetFileName
.Length
;
476 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
;
477 RtlCopyMemory(pBufTail
, TargetFileName
.Buffer
, TargetFileName
.Length
);
479 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
480 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameLength
= cbPrintName
;
481 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
;
482 RtlCopyMemory(pBufTail
, lpTargetFileName
, cbPrintName
);
484 pReparseData
->SymbolicLinkReparseBuffer
.Flags
= 0;
487 pReparseData
->SymbolicLinkReparseBuffer
.Flags
|= 1; // TODO! give this lone flag a name
489 if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName
, &SymlinkFileName
, NULL
, NULL
))
491 dwErr
= ERROR_PATH_NOT_FOUND
;
495 InitializeObjectAttributes(&ObjectAttributes
, &SymlinkFileName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
497 Status
= NtCreateFile
500 FILE_WRITE_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
504 FILE_ATTRIBUTE_NORMAL
,
507 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
| dwCreateOptions
,
512 if(!NT_SUCCESS(Status
))
514 dwErr
= RtlNtStatusToDosError(Status
);
518 Status
= NtFsControlFile
525 FSCTL_SET_REPARSE_POINT
,
532 if(!NT_SUCCESS(Status
))
534 FILE_DISPOSITION_INFORMATION DispInfo
;
535 DispInfo
.DeleteFile
= TRUE
;
536 NtSetInformationFile(hSymlink
, &IoStatusBlock
, &DispInfo
, sizeof(DispInfo
), FileDispositionInformation
);
538 dwErr
= RtlNtStatusToDosError(Status
);
548 RtlFreeUnicodeString(&SymlinkFileName
);
549 if (bAllocatedTarget
)
551 RtlFreeHeap(RtlGetProcessHeap(),
553 TargetFileName
.Buffer
);
556 if(lpTargetFullFileName
)
557 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName
);
560 RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData
);
576 CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName
,
577 IN LPCSTR lpTargetFileName
,
580 PWCHAR SymlinkW
, TargetW
;
583 if(!lpSymlinkFileName
|| !lpTargetFileName
)
585 SetLastError(ERROR_INVALID_PARAMETER
);
589 if (!(SymlinkW
= FilenameA2W(lpSymlinkFileName
, FALSE
)))
592 if (!(TargetW
= FilenameA2W(lpTargetFileName
, TRUE
)))
595 Ret
= CreateSymbolicLinkW(SymlinkW
,
599 RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW
);
600 RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW
);