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 *****************************************************************/
18 #include <wine/debug.h>
20 WINE_DEFAULT_DEBUG_CHANNEL(kernel32file
);
22 #define SYMLINK_FLAG_RELATIVE 1
24 typedef struct _REPARSE_DATA_BUFFER
{
26 USHORT ReparseDataLength
;
30 USHORT SubstituteNameOffset
;
31 USHORT SubstituteNameLength
;
32 USHORT PrintNameOffset
;
33 USHORT PrintNameLength
;
36 } SymbolicLinkReparseBuffer
;
38 USHORT SubstituteNameOffset
;
39 USHORT SubstituteNameLength
;
40 USHORT PrintNameOffset
;
41 USHORT PrintNameLength
;
43 } MountPointReparseBuffer
;
46 } GenericReparseBuffer
;
48 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
50 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
52 /* FUNCTIONS ****************************************************************/
57 HANDLE WINAPI
CreateFileA (LPCSTR lpFileName
,
58 DWORD dwDesiredAccess
,
60 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
61 DWORD dwCreationDisposition
,
62 DWORD dwFlagsAndAttributes
,
68 TRACE("CreateFileA(lpFileName %s)\n",lpFileName
);
70 if (!(FileNameW
= FilenameA2W(lpFileName
, FALSE
)))
71 return INVALID_HANDLE_VALUE
;
73 FileHandle
= CreateFileW (FileNameW
,
77 dwCreationDisposition
,
88 HANDLE WINAPI
CreateFileW (LPCWSTR lpFileName
,
89 DWORD dwDesiredAccess
,
91 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
92 DWORD dwCreationDisposition
,
93 DWORD dwFlagsAndAttributes
,
96 OBJECT_ATTRIBUTES ObjectAttributes
;
97 IO_STATUS_BLOCK IoStatusBlock
;
98 UNICODE_STRING NtPathU
;
101 ULONG FileAttributes
, Flags
= 0;
102 PVOID EaBuffer
= NULL
;
105 TRACE("CreateFileW(lpFileName %S)\n",lpFileName
);
107 /* validate & translate the creation disposition */
108 switch (dwCreationDisposition
)
111 dwCreationDisposition
= FILE_CREATE
;
115 dwCreationDisposition
= FILE_OVERWRITE_IF
;
119 dwCreationDisposition
= FILE_OPEN
;
123 dwCreationDisposition
= FILE_OPEN_IF
;
126 case TRUNCATE_EXISTING
:
127 dwCreationDisposition
= FILE_OVERWRITE
;
131 SetLastError(ERROR_INVALID_PARAMETER
);
132 return (INVALID_HANDLE_VALUE
);
135 /* check for console input/output */
136 if (0 == _wcsicmp(L
"CONOUT$", lpFileName
)
137 || 0 == _wcsicmp(L
"CONIN$", lpFileName
))
139 return OpenConsoleW(lpFileName
,
141 lpSecurityAttributes
? lpSecurityAttributes
->bInheritHandle
: FALSE
,
142 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
145 /* validate & translate the flags */
147 /* translate the flags that need no validation */
148 if (!(dwFlagsAndAttributes
& FILE_FLAG_OVERLAPPED
))
150 /* yes, nonalert is correct! apc's are not delivered
151 while waiting for file io to complete */
152 Flags
|= FILE_SYNCHRONOUS_IO_NONALERT
;
155 if(dwFlagsAndAttributes
& FILE_FLAG_WRITE_THROUGH
)
156 Flags
|= FILE_WRITE_THROUGH
;
158 if(dwFlagsAndAttributes
& FILE_FLAG_NO_BUFFERING
)
159 Flags
|= FILE_NO_INTERMEDIATE_BUFFERING
;
161 if(dwFlagsAndAttributes
& FILE_FLAG_RANDOM_ACCESS
)
162 Flags
|= FILE_RANDOM_ACCESS
;
164 if(dwFlagsAndAttributes
& FILE_FLAG_SEQUENTIAL_SCAN
)
165 Flags
|= FILE_SEQUENTIAL_ONLY
;
167 if(dwFlagsAndAttributes
& FILE_FLAG_DELETE_ON_CLOSE
)
168 Flags
|= FILE_DELETE_ON_CLOSE
;
170 if(dwFlagsAndAttributes
& FILE_FLAG_BACKUP_SEMANTICS
)
172 if(dwDesiredAccess
& GENERIC_ALL
)
173 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_FOR_RECOVERY
;
176 if(dwDesiredAccess
& GENERIC_READ
)
177 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
;
179 if(dwDesiredAccess
& GENERIC_WRITE
)
180 Flags
|= FILE_OPEN_FOR_RECOVERY
;
184 Flags
|= FILE_NON_DIRECTORY_FILE
;
186 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_REPARSE_POINT
)
187 Flags
|= FILE_OPEN_REPARSE_POINT
;
189 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_NO_RECALL
)
190 Flags
|= FILE_OPEN_NO_RECALL
;
192 FileAttributes
= (dwFlagsAndAttributes
& (FILE_ATTRIBUTE_VALID_FLAGS
& ~FILE_ATTRIBUTE_DIRECTORY
));
194 /* handle may allways be waited on and querying attributes are allways allowed */
195 dwDesiredAccess
|= SYNCHRONIZE
| FILE_READ_ATTRIBUTES
;
197 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
199 /* validate & translate the filename */
200 if (!RtlDosPathNameToNtPathName_U (lpFileName
,
205 WARN("Invalid path\n");
206 SetLastError(ERROR_PATH_NOT_FOUND
);
207 return INVALID_HANDLE_VALUE
;
210 TRACE("NtPathU \'%wZ\'\n", &NtPathU
);
212 if (hTemplateFile
!= NULL
)
214 FILE_EA_INFORMATION EaInformation
;
218 /* try to get the size of the extended attributes, if we fail just continue
219 creating the file without copying the attributes! */
220 Status
= NtQueryInformationFile(hTemplateFile
,
223 sizeof(FILE_EA_INFORMATION
),
225 if (NT_SUCCESS(Status
) && (EaInformation
.EaSize
!= 0))
227 /* there's extended attributes to read, let's give it a try */
228 EaBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
230 EaInformation
.EaSize
);
231 if (EaBuffer
== NULL
)
233 RtlFreeHeap(RtlGetProcessHeap(),
237 /* the template file handle is valid and has extended attributes,
238 however we seem to lack some memory here. We should fail here! */
239 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
240 return INVALID_HANDLE_VALUE
;
243 Status
= NtQueryEaFile(hTemplateFile
,
246 EaInformation
.EaSize
,
253 if (NT_SUCCESS(Status
))
255 /* we successfully read the extended attributes, break the loop
257 EaLength
= EaInformation
.EaSize
;
262 RtlFreeHeap(RtlGetProcessHeap(),
267 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
269 /* unless we just allocated not enough memory, break the loop
270 and just continue without copying extended attributes */
277 /* we either failed to get the size of the extended attributes or
278 they're empty, just continue as there's no need to copy
285 /* build the object attributes */
286 InitializeObjectAttributes(&ObjectAttributes
,
292 if (lpSecurityAttributes
)
294 if(lpSecurityAttributes
->bInheritHandle
)
295 ObjectAttributes
.Attributes
|= OBJ_INHERIT
;
297 ObjectAttributes
.SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
300 if(!(dwFlagsAndAttributes
& FILE_FLAG_POSIX_SEMANTICS
))
301 ObjectAttributes
.Attributes
|= OBJ_CASE_INSENSITIVE
;
303 /* perform the call */
304 Status
= NtCreateFile (&FileHandle
,
311 dwCreationDisposition
,
316 RtlFreeHeap(RtlGetProcessHeap(),
320 /* free the extended attributes buffer if allocated */
321 if (EaBuffer
!= NULL
)
323 RtlFreeHeap(RtlGetProcessHeap(),
329 if (!NT_SUCCESS(Status
))
331 /* In the case file creation was rejected due to CREATE_NEW flag
332 * was specified and file with that name already exists, correct
333 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
334 * Note: RtlNtStatusToDosError is not the subject to blame here.
336 if (Status
== STATUS_OBJECT_NAME_COLLISION
&&
337 dwCreationDisposition
== FILE_CREATE
)
339 SetLastError( ERROR_FILE_EXISTS
);
343 SetLastErrorByStatus (Status
);
346 return INVALID_HANDLE_VALUE
;
350 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
351 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
353 if (dwCreationDisposition
== FILE_OPEN_IF
)
355 SetLastError(IoStatusBlock
.Information
== FILE_OPENED
? ERROR_ALREADY_EXISTS
: 0);
357 else if (dwCreationDisposition
== FILE_OVERWRITE_IF
)
359 SetLastError(IoStatusBlock
.Information
== FILE_OVERWRITTEN
? ERROR_ALREADY_EXISTS
: 0);
371 CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName
,
372 IN LPCWSTR lpTargetFileName
,
375 IO_STATUS_BLOCK IoStatusBlock
;
376 OBJECT_ATTRIBUTES ObjectAttributes
;
377 HANDLE hSymlink
= NULL
;
378 UNICODE_STRING SymlinkFileName
= { 0, 0, NULL
};
379 UNICODE_STRING TargetFileName
= { 0, 0, NULL
};
380 BOOLEAN bAllocatedTarget
= FALSE
, bRelativePath
= FALSE
;
381 LPWSTR lpTargetFullFileName
= NULL
;
383 SIZE_T cbReparseData
;
384 PREPARSE_DATA_BUFFER pReparseData
= NULL
;
387 ULONG dwCreateOptions
;
390 if(!lpSymlinkFileName
|| !lpTargetFileName
|| (dwFlags
| SYMBOLIC_LINK_FLAG_DIRECTORY
) != SYMBOLIC_LINK_FLAG_DIRECTORY
)
392 SetLastError(ERROR_INVALID_PARAMETER
);
396 if(dwFlags
& SYMBOLIC_LINK_FLAG_DIRECTORY
)
397 dwCreateOptions
= FILE_DIRECTORY_FILE
;
399 dwCreateOptions
= FILE_NON_DIRECTORY_FILE
;
401 switch(RtlDetermineDosPathNameType_U(lpTargetFileName
))
403 case RtlPathTypeUnknown
:
404 case RtlPathTypeRooted
:
405 case RtlPathTypeRelative
:
406 bRelativePath
= TRUE
;
407 RtlInitUnicodeString(&TargetFileName
, lpTargetFileName
);
410 case RtlPathTypeDriveRelative
:
413 SIZE_T cchTargetFullFileName
;
415 cchTargetFullFileName
= GetFullPathNameW(lpTargetFileName
, 0, NULL
, &FilePart
);
417 if(cchTargetFullFileName
== 0)
419 dwErr
= GetLastError();
423 lpTargetFullFileName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName
* sizeof(WCHAR
));
425 if(lpTargetFullFileName
== NULL
)
427 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
431 if(GetFullPathNameW(lpTargetFileName
, cchTargetFullFileName
, lpTargetFullFileName
, &FilePart
) == 0)
433 dwErr
= GetLastError();
438 lpTargetFileName
= lpTargetFullFileName
;
442 case RtlPathTypeUncAbsolute
:
443 case RtlPathTypeDriveAbsolute
:
444 case RtlPathTypeLocalDevice
:
445 case RtlPathTypeRootLocalDevice
:
447 if(!RtlDosPathNameToNtPathName_U(lpTargetFileName
, &TargetFileName
, NULL
, NULL
))
449 bAllocatedTarget
= TRUE
;
450 dwErr
= ERROR_INVALID_PARAMETER
;
455 cbPrintName
= wcslen(lpTargetFileName
) * sizeof(WCHAR
);
456 cbReparseData
= FIELD_OFFSET(REPARSE_DATA_BUFFER
, SymbolicLinkReparseBuffer
.PathBuffer
) + TargetFileName
.Length
+ cbPrintName
;
457 pReparseData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData
);
459 if(pReparseData
== NULL
)
461 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
465 pBufTail
= (PBYTE
)(pReparseData
->SymbolicLinkReparseBuffer
.PathBuffer
);
467 pReparseData
->ReparseTag
= (ULONG
)IO_REPARSE_TAG_SYMLINK
;
468 pReparseData
->ReparseDataLength
= (USHORT
)cbReparseData
- REPARSE_DATA_BUFFER_HEADER_SIZE
;
469 pReparseData
->Reserved
= 0;
471 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
= 0;
472 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
= TargetFileName
.Length
;
473 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
;
474 RtlCopyMemory(pBufTail
, TargetFileName
.Buffer
, TargetFileName
.Length
);
476 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
477 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameLength
= (USHORT
)cbPrintName
;
478 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
;
479 RtlCopyMemory(pBufTail
, lpTargetFileName
, cbPrintName
);
481 pReparseData
->SymbolicLinkReparseBuffer
.Flags
= 0;
484 pReparseData
->SymbolicLinkReparseBuffer
.Flags
|= 1; // TODO! give this lone flag a name
486 if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName
, &SymlinkFileName
, NULL
, NULL
))
488 dwErr
= ERROR_PATH_NOT_FOUND
;
492 InitializeObjectAttributes(&ObjectAttributes
, &SymlinkFileName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
494 Status
= NtCreateFile
497 FILE_WRITE_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
501 FILE_ATTRIBUTE_NORMAL
,
504 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
| dwCreateOptions
,
509 if(!NT_SUCCESS(Status
))
511 dwErr
= RtlNtStatusToDosError(Status
);
515 Status
= NtFsControlFile
522 FSCTL_SET_REPARSE_POINT
,
529 if(!NT_SUCCESS(Status
))
531 FILE_DISPOSITION_INFORMATION DispInfo
;
532 DispInfo
.DeleteFile
= TRUE
;
533 NtSetInformationFile(hSymlink
, &IoStatusBlock
, &DispInfo
, sizeof(DispInfo
), FileDispositionInformation
);
535 dwErr
= RtlNtStatusToDosError(Status
);
545 RtlFreeUnicodeString(&SymlinkFileName
);
546 if (bAllocatedTarget
)
548 RtlFreeHeap(RtlGetProcessHeap(),
550 TargetFileName
.Buffer
);
553 if(lpTargetFullFileName
)
554 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName
);
557 RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData
);
574 CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName
,
575 IN LPCSTR lpTargetFileName
,
578 PWCHAR SymlinkW
, TargetW
;
581 if(!lpSymlinkFileName
|| !lpTargetFileName
)
583 SetLastError(ERROR_INVALID_PARAMETER
);
587 if (!(SymlinkW
= FilenameA2W(lpSymlinkFileName
, FALSE
)))
590 if (!(TargetW
= FilenameA2W(lpTargetFileName
, TRUE
)))
593 Ret
= CreateSymbolicLinkW(SymlinkW
,
597 RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW
);
598 RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW
);