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 *****************************************************************/
21 #define SYMLINK_FLAG_RELATIVE 1
23 typedef struct _REPARSE_DATA_BUFFER
{
25 USHORT ReparseDataLength
;
29 USHORT SubstituteNameOffset
;
30 USHORT SubstituteNameLength
;
31 USHORT PrintNameOffset
;
32 USHORT PrintNameLength
;
35 } SymbolicLinkReparseBuffer
;
37 USHORT SubstituteNameOffset
;
38 USHORT SubstituteNameLength
;
39 USHORT PrintNameOffset
;
40 USHORT PrintNameLength
;
42 } MountPointReparseBuffer
;
45 } GenericReparseBuffer
;
47 } REPARSE_DATA_BUFFER
, *PREPARSE_DATA_BUFFER
;
49 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
51 /* FUNCTIONS ****************************************************************/
56 HANDLE WINAPI
CreateFileA (LPCSTR lpFileName
,
57 DWORD dwDesiredAccess
,
59 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
60 DWORD dwCreationDisposition
,
61 DWORD dwFlagsAndAttributes
,
67 TRACE("CreateFileA(lpFileName %s)\n",lpFileName
);
69 if (!(FileNameW
= FilenameA2W(lpFileName
, FALSE
)))
70 return INVALID_HANDLE_VALUE
;
72 FileHandle
= CreateFileW (FileNameW
,
76 dwCreationDisposition
,
87 HANDLE WINAPI
CreateFileW (LPCWSTR lpFileName
,
88 DWORD dwDesiredAccess
,
90 LPSECURITY_ATTRIBUTES lpSecurityAttributes
,
91 DWORD dwCreationDisposition
,
92 DWORD dwFlagsAndAttributes
,
95 OBJECT_ATTRIBUTES ObjectAttributes
;
96 IO_STATUS_BLOCK IoStatusBlock
;
97 UNICODE_STRING NtPathU
;
100 ULONG FileAttributes
, Flags
= 0;
101 PVOID EaBuffer
= NULL
;
104 if (!lpFileName
|| !lpFileName
[0])
106 SetLastError( ERROR_PATH_NOT_FOUND
);
107 return INVALID_HANDLE_VALUE
;
110 TRACE("CreateFileW(lpFileName %S)\n",lpFileName
);
112 /* validate & translate the creation disposition */
113 switch (dwCreationDisposition
)
116 dwCreationDisposition
= FILE_CREATE
;
120 dwCreationDisposition
= FILE_OVERWRITE_IF
;
124 dwCreationDisposition
= FILE_OPEN
;
128 dwCreationDisposition
= FILE_OPEN_IF
;
131 case TRUNCATE_EXISTING
:
132 dwCreationDisposition
= FILE_OVERWRITE
;
136 SetLastError(ERROR_INVALID_PARAMETER
);
137 return (INVALID_HANDLE_VALUE
);
140 /* check for console input/output */
141 if (0 == _wcsicmp(L
"CONOUT$", lpFileName
)
142 || 0 == _wcsicmp(L
"CONIN$", lpFileName
))
144 return OpenConsoleW(lpFileName
,
146 lpSecurityAttributes
? lpSecurityAttributes
->bInheritHandle
: FALSE
,
147 FILE_SHARE_READ
| FILE_SHARE_WRITE
);
150 /* validate & translate the flags */
152 /* translate the flags that need no validation */
153 if (!(dwFlagsAndAttributes
& FILE_FLAG_OVERLAPPED
))
155 /* yes, nonalert is correct! apc's are not delivered
156 while waiting for file io to complete */
157 Flags
|= FILE_SYNCHRONOUS_IO_NONALERT
;
160 if(dwFlagsAndAttributes
& FILE_FLAG_WRITE_THROUGH
)
161 Flags
|= FILE_WRITE_THROUGH
;
163 if(dwFlagsAndAttributes
& FILE_FLAG_NO_BUFFERING
)
164 Flags
|= FILE_NO_INTERMEDIATE_BUFFERING
;
166 if(dwFlagsAndAttributes
& FILE_FLAG_RANDOM_ACCESS
)
167 Flags
|= FILE_RANDOM_ACCESS
;
169 if(dwFlagsAndAttributes
& FILE_FLAG_SEQUENTIAL_SCAN
)
170 Flags
|= FILE_SEQUENTIAL_ONLY
;
172 if(dwFlagsAndAttributes
& FILE_FLAG_DELETE_ON_CLOSE
)
173 Flags
|= FILE_DELETE_ON_CLOSE
;
175 if(dwFlagsAndAttributes
& FILE_FLAG_BACKUP_SEMANTICS
)
177 if(dwDesiredAccess
& GENERIC_ALL
)
178 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
| FILE_OPEN_REMOTE_INSTANCE
;
181 if(dwDesiredAccess
& GENERIC_READ
)
182 Flags
|= FILE_OPEN_FOR_BACKUP_INTENT
;
184 if(dwDesiredAccess
& GENERIC_WRITE
)
185 Flags
|= FILE_OPEN_REMOTE_INSTANCE
;
189 Flags
|= FILE_NON_DIRECTORY_FILE
;
191 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_REPARSE_POINT
)
192 Flags
|= FILE_OPEN_REPARSE_POINT
;
194 if(dwFlagsAndAttributes
& FILE_FLAG_OPEN_NO_RECALL
)
195 Flags
|= FILE_OPEN_NO_RECALL
;
197 FileAttributes
= (dwFlagsAndAttributes
& (FILE_ATTRIBUTE_VALID_FLAGS
& ~FILE_ATTRIBUTE_DIRECTORY
));
199 /* handle may allways be waited on and querying attributes are allways allowed */
200 dwDesiredAccess
|= SYNCHRONIZE
| FILE_READ_ATTRIBUTES
;
202 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
204 /* validate & translate the filename */
205 if (!RtlDosPathNameToNtPathName_U (lpFileName
,
210 WARN("Invalid path\n");
211 SetLastError(ERROR_PATH_NOT_FOUND
);
212 return INVALID_HANDLE_VALUE
;
215 TRACE("NtPathU \'%wZ\'\n", &NtPathU
);
217 if (hTemplateFile
!= NULL
)
219 FILE_EA_INFORMATION EaInformation
;
223 /* try to get the size of the extended attributes, if we fail just continue
224 creating the file without copying the attributes! */
225 Status
= NtQueryInformationFile(hTemplateFile
,
228 sizeof(FILE_EA_INFORMATION
),
230 if (NT_SUCCESS(Status
) && (EaInformation
.EaSize
!= 0))
232 /* there's extended attributes to read, let's give it a try */
233 EaBuffer
= RtlAllocateHeap(RtlGetProcessHeap(),
235 EaInformation
.EaSize
);
236 if (EaBuffer
== NULL
)
238 RtlFreeHeap(RtlGetProcessHeap(),
242 /* the template file handle is valid and has extended attributes,
243 however we seem to lack some memory here. We should fail here! */
244 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
245 return INVALID_HANDLE_VALUE
;
248 Status
= NtQueryEaFile(hTemplateFile
,
251 EaInformation
.EaSize
,
258 if (NT_SUCCESS(Status
))
260 /* we successfully read the extended attributes, break the loop
262 EaLength
= EaInformation
.EaSize
;
267 RtlFreeHeap(RtlGetProcessHeap(),
272 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
274 /* unless we just allocated not enough memory, break the loop
275 and just continue without copying extended attributes */
282 /* we either failed to get the size of the extended attributes or
283 they're empty, just continue as there's no need to copy
290 /* build the object attributes */
291 InitializeObjectAttributes(&ObjectAttributes
,
297 if (lpSecurityAttributes
)
299 if(lpSecurityAttributes
->bInheritHandle
)
300 ObjectAttributes
.Attributes
|= OBJ_INHERIT
;
302 ObjectAttributes
.SecurityDescriptor
= lpSecurityAttributes
->lpSecurityDescriptor
;
305 if(!(dwFlagsAndAttributes
& FILE_FLAG_POSIX_SEMANTICS
))
306 ObjectAttributes
.Attributes
|= OBJ_CASE_INSENSITIVE
;
308 /* perform the call */
309 Status
= NtCreateFile (&FileHandle
,
316 dwCreationDisposition
,
321 RtlFreeHeap(RtlGetProcessHeap(),
325 /* free the extended attributes buffer if allocated */
326 if (EaBuffer
!= NULL
)
328 RtlFreeHeap(RtlGetProcessHeap(),
334 if (!NT_SUCCESS(Status
))
336 /* In the case file creation was rejected due to CREATE_NEW flag
337 * was specified and file with that name already exists, correct
338 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
339 * Note: RtlNtStatusToDosError is not the subject to blame here.
341 if (Status
== STATUS_OBJECT_NAME_COLLISION
&&
342 dwCreationDisposition
== FILE_CREATE
)
344 SetLastError( ERROR_FILE_EXISTS
);
348 SetLastErrorByStatus (Status
);
351 return INVALID_HANDLE_VALUE
;
355 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
356 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
358 if (dwCreationDisposition
== FILE_OPEN_IF
)
360 SetLastError(IoStatusBlock
.Information
== FILE_OPENED
? ERROR_ALREADY_EXISTS
: 0);
362 else if (dwCreationDisposition
== FILE_OVERWRITE_IF
)
364 SetLastError(IoStatusBlock
.Information
== FILE_OVERWRITTEN
? ERROR_ALREADY_EXISTS
: 0);
376 CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName
,
377 IN LPCWSTR lpTargetFileName
,
380 IO_STATUS_BLOCK IoStatusBlock
;
381 OBJECT_ATTRIBUTES ObjectAttributes
;
382 HANDLE hSymlink
= NULL
;
383 UNICODE_STRING SymlinkFileName
= { 0, 0, NULL
};
384 UNICODE_STRING TargetFileName
= { 0, 0, NULL
};
385 BOOLEAN bAllocatedTarget
= FALSE
, bRelativePath
= FALSE
;
386 LPWSTR lpTargetFullFileName
= NULL
;
388 SIZE_T cbReparseData
;
389 PREPARSE_DATA_BUFFER pReparseData
= NULL
;
392 ULONG dwCreateOptions
;
395 if(!lpSymlinkFileName
|| !lpTargetFileName
|| (dwFlags
| SYMBOLIC_LINK_FLAG_DIRECTORY
) != SYMBOLIC_LINK_FLAG_DIRECTORY
)
397 SetLastError(ERROR_INVALID_PARAMETER
);
401 if(dwFlags
& SYMBOLIC_LINK_FLAG_DIRECTORY
)
402 dwCreateOptions
= FILE_DIRECTORY_FILE
;
404 dwCreateOptions
= FILE_NON_DIRECTORY_FILE
;
406 switch(RtlDetermineDosPathNameType_U(lpTargetFileName
))
408 case RtlPathTypeUnknown
:
409 case RtlPathTypeRooted
:
410 case RtlPathTypeRelative
:
411 bRelativePath
= TRUE
;
412 RtlInitUnicodeString(&TargetFileName
, lpTargetFileName
);
415 case RtlPathTypeDriveRelative
:
418 SIZE_T cchTargetFullFileName
;
420 cchTargetFullFileName
= GetFullPathNameW(lpTargetFileName
, 0, NULL
, &FilePart
);
422 if(cchTargetFullFileName
== 0)
424 dwErr
= GetLastError();
428 lpTargetFullFileName
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName
* sizeof(WCHAR
));
430 if(lpTargetFullFileName
== NULL
)
432 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
436 if(GetFullPathNameW(lpTargetFileName
, cchTargetFullFileName
, lpTargetFullFileName
, &FilePart
) == 0)
438 dwErr
= GetLastError();
443 lpTargetFileName
= lpTargetFullFileName
;
447 case RtlPathTypeUncAbsolute
:
448 case RtlPathTypeDriveAbsolute
:
449 case RtlPathTypeLocalDevice
:
450 case RtlPathTypeRootLocalDevice
:
452 if(!RtlDosPathNameToNtPathName_U(lpTargetFileName
, &TargetFileName
, NULL
, NULL
))
454 bAllocatedTarget
= TRUE
;
455 dwErr
= ERROR_INVALID_PARAMETER
;
460 cbPrintName
= wcslen(lpTargetFileName
) * sizeof(WCHAR
);
461 cbReparseData
= FIELD_OFFSET(REPARSE_DATA_BUFFER
, SymbolicLinkReparseBuffer
.PathBuffer
) + TargetFileName
.Length
+ cbPrintName
;
462 pReparseData
= RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData
);
464 if(pReparseData
== NULL
)
466 dwErr
= ERROR_NOT_ENOUGH_MEMORY
;
470 pBufTail
= (PBYTE
)(pReparseData
->SymbolicLinkReparseBuffer
.PathBuffer
);
472 pReparseData
->ReparseTag
= (ULONG
)IO_REPARSE_TAG_SYMLINK
;
473 pReparseData
->ReparseDataLength
= (USHORT
)cbReparseData
- REPARSE_DATA_BUFFER_HEADER_SIZE
;
474 pReparseData
->Reserved
= 0;
476 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
= 0;
477 pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
= TargetFileName
.Length
;
478 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameOffset
;
479 RtlCopyMemory(pBufTail
, TargetFileName
.Buffer
, TargetFileName
.Length
);
481 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
= pReparseData
->SymbolicLinkReparseBuffer
.SubstituteNameLength
;
482 pReparseData
->SymbolicLinkReparseBuffer
.PrintNameLength
= (USHORT
)cbPrintName
;
483 pBufTail
+= pReparseData
->SymbolicLinkReparseBuffer
.PrintNameOffset
;
484 RtlCopyMemory(pBufTail
, lpTargetFileName
, cbPrintName
);
486 pReparseData
->SymbolicLinkReparseBuffer
.Flags
= 0;
489 pReparseData
->SymbolicLinkReparseBuffer
.Flags
|= 1; // TODO! give this lone flag a name
491 if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName
, &SymlinkFileName
, NULL
, NULL
))
493 dwErr
= ERROR_PATH_NOT_FOUND
;
497 InitializeObjectAttributes(&ObjectAttributes
, &SymlinkFileName
, OBJ_CASE_INSENSITIVE
, NULL
, NULL
);
499 Status
= NtCreateFile
502 FILE_WRITE_ATTRIBUTES
| DELETE
| SYNCHRONIZE
,
506 FILE_ATTRIBUTE_NORMAL
,
509 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_OPEN_REPARSE_POINT
| dwCreateOptions
,
514 if(!NT_SUCCESS(Status
))
516 dwErr
= RtlNtStatusToDosError(Status
);
520 Status
= NtFsControlFile
527 FSCTL_SET_REPARSE_POINT
,
534 if(!NT_SUCCESS(Status
))
536 FILE_DISPOSITION_INFORMATION DispInfo
;
537 DispInfo
.DeleteFile
= TRUE
;
538 NtSetInformationFile(hSymlink
, &IoStatusBlock
, &DispInfo
, sizeof(DispInfo
), FileDispositionInformation
);
540 dwErr
= RtlNtStatusToDosError(Status
);
550 RtlFreeUnicodeString(&SymlinkFileName
);
551 if (bAllocatedTarget
)
553 RtlFreeHeap(RtlGetProcessHeap(),
555 TargetFileName
.Buffer
);
558 if(lpTargetFullFileName
)
559 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName
);
562 RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData
);
579 CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName
,
580 IN LPCSTR lpTargetFileName
,
583 PWCHAR SymlinkW
, TargetW
;
586 if(!lpSymlinkFileName
|| !lpTargetFileName
)
588 SetLastError(ERROR_INVALID_PARAMETER
);
592 if (!(SymlinkW
= FilenameA2W(lpSymlinkFileName
, FALSE
)))
595 if (!(TargetW
= FilenameA2W(lpTargetFileName
, TRUE
)))
598 Ret
= CreateSymbolicLinkW(SymlinkW
,
602 RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW
);
603 RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW
);