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 *****************************************************************/
20 static ULONG gDebugChannel
= 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 if (!lpFileName
|| !lpFileName
[0])
107 SetLastError( ERROR_PATH_NOT_FOUND
);
108 return INVALID_HANDLE_VALUE
;
111 TRACE("CreateFileW(lpFileName %S)\n",lpFileName
);
113 /* validate & translate the creation disposition */
114 switch (dwCreationDisposition
)
117 dwCreationDisposition
= FILE_CREATE
;
121 dwCreationDisposition
= FILE_OVERWRITE_IF
;
125 dwCreationDisposition
= FILE_OPEN
;
129 dwCreationDisposition
= FILE_OPEN_IF
;
132 case TRUNCATE_EXISTING
:
133 dwCreationDisposition
= FILE_OVERWRITE
;
137 SetLastError(ERROR_INVALID_PARAMETER
);
138 return (INVALID_HANDLE_VALUE
);
141 /* check for console input/output */
142 if (0 == _wcsicmp(L
"CONOUT$", lpFileName
)
143 || 0 == _wcsicmp(L
"CONIN$", lpFileName
))
145 return OpenConsoleW(lpFileName
,
147 lpSecurityAttributes
? lpSecurityAttributes
->bInheritHandle
: FALSE
,
148 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
151 /* validate & translate the flags */
153 /* translate the flags that need no validation */
154 if (!(dwFlagsAndAttributes
& FILE_FLAG_OVERLAPPED
))
156 /* yes, nonalert is correct! apc's are not delivered
157 while waiting for file io to complete */
158 Flags
|= FILE_SYNCHRONOUS_IO_NONALERT
;
161 if(dwFlagsAndAttributes
& FILE_FLAG_WRITE_THROUGH
)
162 Flags
|= FILE_WRITE_THROUGH
;
164 if(dwFlagsAndAttributes
& FILE_FLAG_NO_BUFFERING
)
165 Flags
|= FILE_NO_INTERMEDIATE_BUFFERING
;
167 if(dwFlagsAndAttributes
& FILE_FLAG_RANDOM_ACCESS
)
168 Flags
|= FILE_RANDOM_ACCESS
;
170 if(dwFlagsAndAttributes
& FILE_FLAG_SEQUENTIAL_SCAN
)
171 Flags
|= FILE_SEQUENTIAL_ONLY
;
173 if(dwFlagsAndAttributes
& FILE_FLAG_DELETE_ON_CLOSE
)
174 Flags
|= FILE_DELETE_ON_CLOSE
;
176 if(dwFlagsAndAttributes
& FILE_FLAG_BACKUP_SEMANTICS
)
178 if(dwDesiredAccess
& GENERIC_ALL
)
179 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REMOTE_INSTANCE
;
182 if(dwDesiredAccess
& GENERIC_READ
)
183 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
;
185 if(dwDesiredAccess
& GENERIC_WRITE
)
186 Flags
|= FILE_OPEN_REMOTE_INSTANCE
;
190 Flags
|= FILE_NON_DIRECTORY_FILE
;
192 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_REPARSE_POINT
)
193 Flags
|= FILE_OPEN_REPARSE_POINT
;
195 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_NO_RECALL
)
196 Flags
|= FILE_OPEN_NO_RECALL
;
198 FileAttributes
= (dwFlagsAndAttributes
& (FILE_ATTRIBUTE_VALID_FLAGS
& ~FILE_ATTRIBUTE_DIRECTORY
));
200 /* handle may allways be waited on and querying attributes are allways allowed */
201 dwDesiredAccess
|= SYNCHRONIZE
| FILE_READ_ATTRIBUTES
;
203 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
205 /* validate & translate the filename */
206 if (!RtlDosPathNameToNtPathName_U (lpFileName
,
211 WARN("Invalid path\n");
212 SetLastError(ERROR_PATH_NOT_FOUND
);
213 return INVALID_HANDLE_VALUE
;
216 TRACE("NtPathU \'%wZ\'\n", &NtPathU
);
218 if (hTemplateFile
!= NULL
)
220 FILE_EA_INFORMATION EaInformation
;
224 /* try to get the size of the extended attributes, if we fail just continue
225 creating the file without copying the attributes! */
226 Status
= NtQueryInformationFile(hTemplateFile
,
229 sizeof(FILE_EA_INFORMATION
),
231 if (NT_SUCCESS(Status
) && (EaInformation
.EaSize
!= 0))
233 /* there's extended attributes to read, let's give it a try */
234 EaBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
236 EaInformation
.EaSize
);
237 if (EaBuffer
== NULL
)
239 RtlFreeHeap(RtlGetProcessHeap(),
243 /* the template file handle is valid and has extended attributes,
244 however we seem to lack some memory here. We should fail here! */
245 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
246 return INVALID_HANDLE_VALUE
;
249 Status
= NtQueryEaFile(hTemplateFile
,
252 EaInformation
.EaSize
,
259 if (NT_SUCCESS(Status
))
261 /* we successfully read the extended attributes, break the loop
263 EaLength
= EaInformation
.EaSize
;
268 RtlFreeHeap(RtlGetProcessHeap(),
273 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
275 /* unless we just allocated not enough memory, break the loop
276 and just continue without copying extended attributes */
283 /* we either failed to get the size of the extended attributes or
284 they're empty, just continue as there's no need to copy
291 /* build the object attributes */
292 InitializeObjectAttributes(&ObjectAttributes
,
298 if (lpSecurityAttributes
)
300 if(lpSecurityAttributes
->bInheritHandle
)
301 ObjectAttributes
.Attributes
|= OBJ_INHERIT
;
303 ObjectAttributes
.SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
306 if(!(dwFlagsAndAttributes
& FILE_FLAG_POSIX_SEMANTICS
))
307 ObjectAttributes
.Attributes
|= OBJ_CASE_INSENSITIVE
;
309 /* perform the call */
310 Status
= NtCreateFile (&FileHandle
,
317 dwCreationDisposition
,
322 RtlFreeHeap(RtlGetProcessHeap(),
326 /* free the extended attributes buffer if allocated */
327 if (EaBuffer
!= NULL
)
329 RtlFreeHeap(RtlGetProcessHeap(),
335 if (!NT_SUCCESS(Status
))
337 /* In the case file creation was rejected due to CREATE_NEW flag
338 * was specified and file with that name already exists, correct
339 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
340 * Note: RtlNtStatusToDosError is not the subject to blame here.
342 if (Status
== STATUS_OBJECT_NAME_COLLISION
&&
343 dwCreationDisposition
== FILE_CREATE
)
345 SetLastError( ERROR_FILE_EXISTS
);
349 SetLastErrorByStatus (Status
);
352 return INVALID_HANDLE_VALUE
;
356 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
357 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
359 if (dwCreationDisposition
== FILE_OPEN_IF
)
361 SetLastError(IoStatusBlock
.Information
== FILE_OPENED
? ERROR_ALREADY_EXISTS
: 0);
363 else if (dwCreationDisposition
== FILE_OVERWRITE_IF
)
365 SetLastError(IoStatusBlock
.Information
== FILE_OVERWRITTEN
? ERROR_ALREADY_EXISTS
: 0);
377 CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName
,
378 IN LPCWSTR lpTargetFileName
,
381 IO_STATUS_BLOCK IoStatusBlock
;
382 OBJECT_ATTRIBUTES ObjectAttributes
;
383 HANDLE hSymlink
= NULL
;
384 UNICODE_STRING SymlinkFileName
= { 0, 0, NULL
};
385 UNICODE_STRING TargetFileName
= { 0, 0, NULL
};
386 BOOLEAN bAllocatedTarget
= FALSE
, bRelativePath
= FALSE
;
387 LPWSTR lpTargetFullFileName
= NULL
;
389 SIZE_T cbReparseData
;
390 PREPARSE_DATA_BUFFER pReparseData
= NULL
;
393 ULONG dwCreateOptions
;
396 if(!lpSymlinkFileName
|| !lpTargetFileName
|| (dwFlags
| SYMBOLIC_LINK_FLAG_DIRECTORY
) != SYMBOLIC_LINK_FLAG_DIRECTORY
)
398 SetLastError(ERROR_INVALID_PARAMETER
);
402 if(dwFlags
& SYMBOLIC_LINK_FLAG_DIRECTORY
)
403 dwCreateOptions
= FILE_DIRECTORY_FILE
;
405 dwCreateOptions
= FILE_NON_DIRECTORY_FILE
;
407 switch(RtlDetermineDosPathNameType_U(lpTargetFileName
))
409 case RtlPathTypeUnknown
:
410 case RtlPathTypeRooted
:
411 case RtlPathTypeRelative
:
412 bRelativePath
= TRUE
;
413 RtlInitUnicodeString(&TargetFileName
, lpTargetFileName
);
416 case RtlPathTypeDriveRelative
:
419 SIZE_T cchTargetFullFileName
;
421 cchTargetFullFileName
= GetFullPathNameW(lpTargetFileName
, 0, NULL
, &FilePart
);
423 if(cchTargetFullFileName
== 0)
425 dwErr
= GetLastError();
429 lpTargetFullFileName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName
* sizeof(WCHAR
));
431 if(lpTargetFullFileName
== NULL
)
433 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
437 if(GetFullPathNameW(lpTargetFileName
, cchTargetFullFileName
, lpTargetFullFileName
, &FilePart
) == 0)
439 dwErr
= GetLastError();
444 lpTargetFileName
= lpTargetFullFileName
;
448 case RtlPathTypeUncAbsolute
:
449 case RtlPathTypeDriveAbsolute
:
450 case RtlPathTypeLocalDevice
:
451 case RtlPathTypeRootLocalDevice
:
453 if(!RtlDosPathNameToNtPathName_U(lpTargetFileName
, &TargetFileName
, NULL
, NULL
))
455 bAllocatedTarget
= TRUE
;
456 dwErr
= ERROR_INVALID_PARAMETER
;
461 cbPrintName
= wcslen(lpTargetFileName
) * sizeof(WCHAR
);
462 cbReparseData
= FIELD_OFFSET(REPARSE_DATA_BUFFER
, SymbolicLinkReparseBuffer
.PathBuffer
) + TargetFileName
.Length
+ cbPrintName
;
463 pReparseData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData
);
465 if(pReparseData
== NULL
)
467 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
471 pBufTail
= (PBYTE
)(pReparseData
->SymbolicLinkReparseBuffer
.PathBuffer
);
473 pReparseData
->ReparseTag
= (ULONG
)IO_REPARSE_TAG_SYMLINK
;
474 pReparseData
->ReparseDataLength
= (USHORT
)cbReparseData
- REPARSE_DATA_BUFFER_HEADER_SIZE
;
475 pReparseData
->Reserved
= 0;
477 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
= 0;
478 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
= TargetFileName
.Length
;
479 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
;
480 RtlCopyMemory(pBufTail
, TargetFileName
.Buffer
, TargetFileName
.Length
);
482 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
483 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameLength
= (USHORT
)cbPrintName
;
484 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
;
485 RtlCopyMemory(pBufTail
, lpTargetFileName
, cbPrintName
);
487 pReparseData
->SymbolicLinkReparseBuffer
.Flags
= 0;
490 pReparseData
->SymbolicLinkReparseBuffer
.Flags
|= 1; // TODO! give this lone flag a name
492 if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName
, &SymlinkFileName
, NULL
, NULL
))
494 dwErr
= ERROR_PATH_NOT_FOUND
;
498 InitializeObjectAttributes(&ObjectAttributes
, &SymlinkFileName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
500 Status
= NtCreateFile
503 FILE_WRITE_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
507 FILE_ATTRIBUTE_NORMAL
,
510 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
| dwCreateOptions
,
515 if(!NT_SUCCESS(Status
))
517 dwErr
= RtlNtStatusToDosError(Status
);
521 Status
= NtFsControlFile
528 FSCTL_SET_REPARSE_POINT
,
535 if(!NT_SUCCESS(Status
))
537 FILE_DISPOSITION_INFORMATION DispInfo
;
538 DispInfo
.DeleteFile
= TRUE
;
539 NtSetInformationFile(hSymlink
, &IoStatusBlock
, &DispInfo
, sizeof(DispInfo
), FileDispositionInformation
);
541 dwErr
= RtlNtStatusToDosError(Status
);
551 RtlFreeUnicodeString(&SymlinkFileName
);
552 if (bAllocatedTarget
)
554 RtlFreeHeap(RtlGetProcessHeap(),
556 TargetFileName
.Buffer
);
559 if(lpTargetFullFileName
)
560 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName
);
563 RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData
);
580 CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName
,
581 IN LPCSTR lpTargetFileName
,
584 PWCHAR SymlinkW
, TargetW
;
587 if(!lpSymlinkFileName
|| !lpTargetFileName
)
589 SetLastError(ERROR_INVALID_PARAMETER
);
593 if (!(SymlinkW
= FilenameA2W(lpSymlinkFileName
, FALSE
)))
596 if (!(TargetW
= FilenameA2W(lpTargetFileName
, TRUE
)))
599 Ret
= CreateSymbolicLinkW(SymlinkW
,
603 RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW
);
604 RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW
);