- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[reactos.git] / reactos / dll / win32 / kernel32 / file / create.c
1 /* $Id$
2 *
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)
8 * UPDATE HISTORY:
9 * Created 01/11/98
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)
13 */
14
15 /* INCLUDES *****************************************************************/
16
17 /* File contains Vista Semantics */
18 #undef _WIN32_WINNT
19 #define _WIN32_WINNT 0x0600
20
21 #include <k32.h>
22
23 #define NDEBUG
24 #include "../include/debug.h"
25
26
27 /* FUNCTIONS ****************************************************************/
28
29 /*
30 * @implemented
31 */
32 HANDLE STDCALL CreateFileA (LPCSTR lpFileName,
33 DWORD dwDesiredAccess,
34 DWORD dwShareMode,
35 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
36 DWORD dwCreationDisposition,
37 DWORD dwFlagsAndAttributes,
38 HANDLE hTemplateFile)
39 {
40 PWCHAR FileNameW;
41 HANDLE FileHandle;
42
43 DPRINT("CreateFileA(lpFileName %s)\n",lpFileName);
44
45 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
46 return INVALID_HANDLE_VALUE;
47
48 FileHandle = CreateFileW (FileNameW,
49 dwDesiredAccess,
50 dwShareMode,
51 lpSecurityAttributes,
52 dwCreationDisposition,
53 dwFlagsAndAttributes,
54 hTemplateFile);
55
56 return FileHandle;
57 }
58
59
60 /*
61 * @implemented
62 */
63 HANDLE STDCALL CreateFileW (LPCWSTR lpFileName,
64 DWORD dwDesiredAccess,
65 DWORD dwShareMode,
66 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
67 DWORD dwCreationDisposition,
68 DWORD dwFlagsAndAttributes,
69 HANDLE hTemplateFile)
70 {
71 OBJECT_ATTRIBUTES ObjectAttributes;
72 IO_STATUS_BLOCK IoStatusBlock;
73 UNICODE_STRING NtPathU;
74 HANDLE FileHandle;
75 NTSTATUS Status;
76 ULONG FileAttributes, Flags = 0;
77 CSR_API_MESSAGE Request;
78 PVOID EaBuffer = NULL;
79 ULONG EaLength = 0;
80
81 DPRINT("CreateFileW(lpFileName %S)\n",lpFileName);
82
83 /* validate & translate the creation disposition */
84 switch (dwCreationDisposition)
85 {
86 case CREATE_NEW:
87 dwCreationDisposition = FILE_CREATE;
88 break;
89
90 case CREATE_ALWAYS:
91 dwCreationDisposition = FILE_OVERWRITE_IF;
92 break;
93
94 case OPEN_EXISTING:
95 dwCreationDisposition = FILE_OPEN;
96 break;
97
98 case OPEN_ALWAYS:
99 dwCreationDisposition = FILE_OPEN_IF;
100 break;
101
102 case TRUNCATE_EXISTING:
103 dwCreationDisposition = FILE_OVERWRITE;
104 break;
105
106 default:
107 SetLastError(ERROR_INVALID_PARAMETER);
108 return (INVALID_HANDLE_VALUE);
109 }
110
111 /* validate & translate the flags */
112
113 /* translate the flags that need no validation */
114 if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
115 {
116 /* yes, nonalert is correct! apc's are not delivered
117 while waiting for file io to complete */
118 Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
119 }
120
121 if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
122 Flags |= FILE_WRITE_THROUGH;
123
124 if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
125 Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
126
127 if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
128 Flags |= FILE_RANDOM_ACCESS;
129
130 if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
131 Flags |= FILE_SEQUENTIAL_ONLY;
132
133 if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
134 Flags |= FILE_DELETE_ON_CLOSE;
135
136 if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
137 {
138 if(dwDesiredAccess & GENERIC_ALL)
139 Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
140 else
141 {
142 if(dwDesiredAccess & GENERIC_READ)
143 Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
144
145 if(dwDesiredAccess & GENERIC_WRITE)
146 Flags |= FILE_OPEN_FOR_RECOVERY;
147 }
148 }
149 else
150 Flags |= FILE_NON_DIRECTORY_FILE;
151
152 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
153 Flags |= FILE_OPEN_REPARSE_POINT;
154
155 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
156 Flags |= FILE_OPEN_NO_RECALL;
157
158 FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
159
160 /* handle may allways be waited on and querying attributes are allways allowed */
161 dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
162
163 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
164
165 /* check for console output */
166 if (0 == _wcsicmp(L"CONOUT$", lpFileName))
167 {
168 /* FIXME: Send required access rights to Csrss */
169 Status = CsrClientCallServer(&Request,
170 NULL,
171 MAKE_CSR_API(GET_OUTPUT_HANDLE, CSR_NATIVE),
172 sizeof(CSR_API_MESSAGE));
173 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
174 {
175 SetLastErrorByStatus(Status);
176 return INVALID_HANDLE_VALUE;
177 }
178 else
179 {
180 return Request.Data.GetOutputHandleRequest.OutputHandle;
181 }
182 }
183
184 /* check for console input */
185 if (0 == _wcsicmp(L"CONIN$", lpFileName))
186 {
187 /* FIXME: Send required access rights to Csrss */
188 Status = CsrClientCallServer(&Request,
189 NULL,
190 MAKE_CSR_API(GET_INPUT_HANDLE, CSR_NATIVE),
191 sizeof(CSR_API_MESSAGE));
192 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
193 {
194 SetLastErrorByStatus(Status);
195 return INVALID_HANDLE_VALUE;
196 }
197 else
198 {
199 return Request.Data.GetInputHandleRequest.InputHandle;
200 }
201 }
202
203 /* validate & translate the filename */
204 if (!RtlDosPathNameToNtPathName_U (lpFileName,
205 &NtPathU,
206 NULL,
207 NULL))
208 {
209 DPRINT("Invalid path\n");
210 SetLastError(ERROR_PATH_NOT_FOUND);
211 return INVALID_HANDLE_VALUE;
212 }
213
214 DPRINT("NtPathU \'%wZ\'\n", &NtPathU);
215
216 if (hTemplateFile != NULL)
217 {
218 FILE_EA_INFORMATION EaInformation;
219
220 for (;;)
221 {
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,
225 &IoStatusBlock,
226 &EaInformation,
227 sizeof(FILE_EA_INFORMATION),
228 FileEaInformation);
229 if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
230 {
231 /* there's extended attributes to read, let's give it a try */
232 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
233 0,
234 EaInformation.EaSize);
235 if (EaBuffer == NULL)
236 {
237 RtlFreeHeap(RtlGetProcessHeap(),
238 0,
239 NtPathU.Buffer);
240
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;
245 }
246
247 Status = NtQueryEaFile(hTemplateFile,
248 &IoStatusBlock,
249 EaBuffer,
250 EaInformation.EaSize,
251 FALSE,
252 NULL,
253 0,
254 NULL,
255 TRUE);
256
257 if (NT_SUCCESS(Status))
258 {
259 /* we successfully read the extended attributes, break the loop
260 and continue */
261 EaLength = EaInformation.EaSize;
262 break;
263 }
264 else
265 {
266 RtlFreeHeap(RtlGetProcessHeap(),
267 0,
268 EaBuffer);
269 EaBuffer = NULL;
270
271 if (Status != STATUS_BUFFER_TOO_SMALL)
272 {
273 /* unless we just allocated not enough memory, break the loop
274 and just continue without copying extended attributes */
275 break;
276 }
277 }
278 }
279 else
280 {
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
283 attributes */
284 break;
285 }
286 }
287 }
288
289 /* build the object attributes */
290 InitializeObjectAttributes(&ObjectAttributes,
291 &NtPathU,
292 0,
293 NULL,
294 NULL);
295
296 if (lpSecurityAttributes)
297 {
298 if(lpSecurityAttributes->bInheritHandle)
299 ObjectAttributes.Attributes |= OBJ_INHERIT;
300
301 ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
302 }
303
304 if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
305 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
306
307 /* perform the call */
308 Status = NtCreateFile (&FileHandle,
309 dwDesiredAccess,
310 &ObjectAttributes,
311 &IoStatusBlock,
312 NULL,
313 FileAttributes,
314 dwShareMode,
315 dwCreationDisposition,
316 Flags,
317 EaBuffer,
318 EaLength);
319
320 RtlFreeHeap(RtlGetProcessHeap(),
321 0,
322 NtPathU.Buffer);
323
324 /* free the extended attributes buffer if allocated */
325 if (EaBuffer != NULL)
326 {
327 RtlFreeHeap(RtlGetProcessHeap(),
328 0,
329 EaBuffer);
330 }
331
332 /* error */
333 if (!NT_SUCCESS(Status))
334 {
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.
339 */
340 if (Status == STATUS_OBJECT_NAME_COLLISION &&
341 dwCreationDisposition == FILE_CREATE)
342 {
343 SetLastError( ERROR_FILE_EXISTS );
344 }
345 else
346 {
347 SetLastErrorByStatus (Status);
348 }
349
350 return INVALID_HANDLE_VALUE;
351 }
352
353 /*
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
356 */
357 if (dwCreationDisposition == FILE_OPEN_IF)
358 {
359 SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
360 }
361 else if (dwCreationDisposition == FILE_OVERWRITE_IF)
362 {
363 SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
364 }
365
366 return FileHandle;
367 }
368
369
370 /*
371 * @implemented
372 */
373 BOOL STDCALL
374 CreateSymbolicLinkW(IN LPCWSTR lpSymlinkFileName,
375 IN LPCWSTR lpTargetFileName,
376 IN DWORD dwFlags)
377 {
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;
385 SIZE_T cbPrintName;
386 SIZE_T cbReparseData;
387 PREPARSE_DATA_BUFFER pReparseData = NULL;
388 PBYTE pBufTail;
389 NTSTATUS Status;
390 ULONG dwCreateOptions;
391 DWORD dwErr;
392
393 if(!lpSymlinkFileName || !lpTargetFileName || (dwFlags | SYMLINK_FLAG_DIRECTORY) != SYMLINK_FLAG_DIRECTORY)
394 {
395 SetLastError(ERROR_INVALID_PARAMETER);
396 return FALSE;
397 }
398
399 if(dwFlags & SYMLINK_FLAG_DIRECTORY)
400 dwCreateOptions = FILE_DIRECTORY_FILE;
401 else
402 dwCreateOptions = FILE_NON_DIRECTORY_FILE;
403
404 switch(RtlDetermineDosPathNameType_U(lpTargetFileName))
405 {
406 case RtlPathTypeUnknown:
407 case RtlPathTypeRooted:
408 case RtlPathTypeRelative:
409 bRelativePath = TRUE;
410 RtlInitUnicodeString(&TargetFileName, lpTargetFileName);
411 break;
412
413 case RtlPathTypeDriveRelative:
414 {
415 LPWSTR FilePart;
416 SIZE_T cchTargetFullFileName;
417
418 cchTargetFullFileName = GetFullPathNameW(lpTargetFileName, 0, NULL, &FilePart);
419
420 if(cchTargetFullFileName == 0)
421 {
422 dwErr = GetLastError();
423 goto Cleanup;
424 }
425
426 lpTargetFullFileName = RtlAllocateHeap(RtlGetProcessHeap(), 0, cchTargetFullFileName * sizeof(WCHAR));
427
428 if(lpTargetFullFileName == NULL)
429 {
430 dwErr = ERROR_NOT_ENOUGH_MEMORY;
431 goto Cleanup;
432 }
433
434 if(GetFullPathNameW(lpTargetFileName, cchTargetFullFileName, lpTargetFullFileName, &FilePart) == 0)
435 {
436 dwErr = GetLastError();
437 goto Cleanup;
438 }
439 }
440
441 lpTargetFileName = lpTargetFullFileName;
442
443 // fallthrough
444
445 case RtlPathTypeUncAbsolute:
446 case RtlPathTypeDriveAbsolute:
447 case RtlPathTypeLocalDevice:
448 case RtlPathTypeRootLocalDevice:
449 default:
450 if(!RtlDosPathNameToNtPathName_U(lpTargetFileName, &TargetFileName, NULL, NULL))
451 {
452 bAllocatedTarget = TRUE;
453 dwErr = ERROR_INVALID_PARAMETER;
454 goto Cleanup;
455 }
456 }
457
458 cbPrintName = wcslen(lpTargetFileName) * sizeof(WCHAR);
459 cbReparseData = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + TargetFileName.Length + cbPrintName;
460 pReparseData = RtlAllocateHeap(RtlGetProcessHeap(), 0, cbReparseData);
461
462 if(pReparseData == NULL)
463 {
464 dwErr = ERROR_NOT_ENOUGH_MEMORY;
465 goto Cleanup;
466 }
467
468 pBufTail = (PBYTE)(pReparseData->SymbolicLinkReparseBuffer.PathBuffer);
469
470 pReparseData->ReparseTag = IO_REPARSE_TAG_SYMLINK;
471 pReparseData->ReparseDataLength = cbReparseData - REPARSE_DATA_BUFFER_HEADER_SIZE;
472 pReparseData->Reserved = 0;
473
474 pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
475 pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength = TargetFileName.Length;
476 pBufTail += pReparseData->SymbolicLinkReparseBuffer.SubstituteNameOffset;
477 RtlCopyMemory(pBufTail, TargetFileName.Buffer, TargetFileName.Length);
478
479 pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset = pReparseData->SymbolicLinkReparseBuffer.SubstituteNameLength;
480 pReparseData->SymbolicLinkReparseBuffer.PrintNameLength = cbPrintName;
481 pBufTail += pReparseData->SymbolicLinkReparseBuffer.PrintNameOffset;
482 RtlCopyMemory(pBufTail, lpTargetFileName, cbPrintName);
483
484 pReparseData->SymbolicLinkReparseBuffer.Flags = 0;
485
486 if(bRelativePath)
487 pReparseData->SymbolicLinkReparseBuffer.Flags |= 1; // TODO! give this lone flag a name
488
489 if(!RtlDosPathNameToNtPathName_U(lpSymlinkFileName, &SymlinkFileName, NULL, NULL))
490 {
491 dwErr = ERROR_PATH_NOT_FOUND;
492 goto Cleanup;
493 }
494
495 InitializeObjectAttributes(&ObjectAttributes, &SymlinkFileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
496
497 Status = NtCreateFile
498 (
499 &hSymlink,
500 FILE_WRITE_ATTRIBUTES | DELETE | SYNCHRONIZE,
501 &ObjectAttributes,
502 &IoStatusBlock,
503 NULL,
504 FILE_ATTRIBUTE_NORMAL,
505 0,
506 FILE_CREATE,
507 FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_REPARSE_POINT | dwCreateOptions,
508 NULL,
509 0
510 );
511
512 if(!NT_SUCCESS(Status))
513 {
514 dwErr = RtlNtStatusToDosError(Status);
515 goto Cleanup;
516 }
517
518 Status = NtFsControlFile
519 (
520 hSymlink,
521 NULL,
522 NULL,
523 NULL,
524 &IoStatusBlock,
525 FSCTL_SET_REPARSE_POINT,
526 pReparseData,
527 cbReparseData,
528 NULL,
529 0
530 );
531
532 if(!NT_SUCCESS(Status))
533 {
534 FILE_DISPOSITION_INFORMATION DispInfo;
535 DispInfo.DeleteFile = TRUE;
536 NtSetInformationFile(hSymlink, &IoStatusBlock, &DispInfo, sizeof(DispInfo), FileDispositionInformation);
537
538 dwErr = RtlNtStatusToDosError(Status);
539 goto Cleanup;
540 }
541
542 dwErr = NO_ERROR;
543
544 Cleanup:
545 if(hSymlink)
546 NtClose(hSymlink);
547
548 RtlFreeUnicodeString(&SymlinkFileName);
549 if (bAllocatedTarget)
550 {
551 RtlFreeHeap(RtlGetProcessHeap(),
552 0,
553 TargetFileName.Buffer);
554 }
555
556 if(lpTargetFullFileName)
557 RtlFreeHeap(RtlGetProcessHeap(), 0, lpTargetFullFileName);
558
559 if(pReparseData)
560 RtlFreeHeap(RtlGetProcessHeap(), 0, pReparseData);
561
562 if(dwErr)
563 {
564 SetLastError(dwErr);
565 return FALSE;
566 }
567
568 return TRUE;
569 }
570
571
572 /*
573 * @implemented
574 */
575 BOOL STDCALL
576 CreateSymbolicLinkA(IN LPCSTR lpSymlinkFileName,
577 IN LPCSTR lpTargetFileName,
578 IN DWORD dwFlags)
579 {
580 PWCHAR SymlinkW, TargetW;
581 BOOL Ret;
582
583 if(!lpSymlinkFileName || !lpTargetFileName)
584 {
585 SetLastError(ERROR_INVALID_PARAMETER);
586 return FALSE;
587 }
588
589 if (!(SymlinkW = FilenameA2W(lpSymlinkFileName, FALSE)))
590 return FALSE;
591
592 if (!(TargetW = FilenameA2W(lpTargetFileName, TRUE)))
593 return FALSE;
594
595 Ret = CreateSymbolicLinkW(SymlinkW,
596 TargetW,
597 dwFlags);
598
599 RtlFreeHeap(RtlGetProcessHeap(), 0, SymlinkW);
600 RtlFreeHeap(RtlGetProcessHeap(), 0, TargetW);
601
602 return Ret;
603 }
604
605
606 /* EOF */