Synchronize up to trunk's revision r57784.
[reactos.git] / dll / win32 / kernel32 / client / file / create.c
1 /* $Id: create.c 54326 2011-11-07 00:18:13Z ion $
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 #include <k32.h>
18 #define NDEBUG
19 #include <debug.h>
20
21 #if DBG
22 DEBUG_CHANNEL(kernel32file);
23 #endif
24
25 #define SYMLINK_FLAG_RELATIVE 1
26
27 typedef struct _REPARSE_DATA_BUFFER {
28 ULONG ReparseTag;
29 USHORT ReparseDataLength;
30 USHORT Reserved;
31 union {
32 struct {
33 USHORT SubstituteNameOffset;
34 USHORT SubstituteNameLength;
35 USHORT PrintNameOffset;
36 USHORT PrintNameLength;
37 ULONG Flags;
38 WCHAR PathBuffer[1];
39 } SymbolicLinkReparseBuffer;
40 struct {
41 USHORT SubstituteNameOffset;
42 USHORT SubstituteNameLength;
43 USHORT PrintNameOffset;
44 USHORT PrintNameLength;
45 WCHAR PathBuffer[1];
46 } MountPointReparseBuffer;
47 struct {
48 UCHAR DataBuffer[1];
49 } GenericReparseBuffer;
50 };
51 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
52
53 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
54
55 /* FUNCTIONS ****************************************************************/
56
57 /*
58 * @implemented
59 */
60 HANDLE WINAPI CreateFileA (LPCSTR lpFileName,
61 DWORD dwDesiredAccess,
62 DWORD dwShareMode,
63 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
64 DWORD dwCreationDisposition,
65 DWORD dwFlagsAndAttributes,
66 HANDLE hTemplateFile)
67 {
68 PWCHAR FileNameW;
69 HANDLE FileHandle;
70
71 TRACE("CreateFileA(lpFileName %s)\n",lpFileName);
72
73 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
74 return INVALID_HANDLE_VALUE;
75
76 FileHandle = CreateFileW (FileNameW,
77 dwDesiredAccess,
78 dwShareMode,
79 lpSecurityAttributes,
80 dwCreationDisposition,
81 dwFlagsAndAttributes,
82 hTemplateFile);
83
84 return FileHandle;
85 }
86
87
88 /*
89 * @implemented
90 */
91 HANDLE WINAPI CreateFileW (LPCWSTR lpFileName,
92 DWORD dwDesiredAccess,
93 DWORD dwShareMode,
94 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
95 DWORD dwCreationDisposition,
96 DWORD dwFlagsAndAttributes,
97 HANDLE hTemplateFile)
98 {
99 OBJECT_ATTRIBUTES ObjectAttributes;
100 IO_STATUS_BLOCK IoStatusBlock;
101 UNICODE_STRING NtPathU;
102 HANDLE FileHandle;
103 NTSTATUS Status;
104 ULONG FileAttributes, Flags = 0;
105 PVOID EaBuffer = NULL;
106 ULONG EaLength = 0;
107
108 if (!lpFileName || !lpFileName[0])
109 {
110 SetLastError( ERROR_PATH_NOT_FOUND );
111 return INVALID_HANDLE_VALUE;
112 }
113
114 TRACE("CreateFileW(lpFileName %S)\n",lpFileName);
115
116 /* validate & translate the creation disposition */
117 switch (dwCreationDisposition)
118 {
119 case CREATE_NEW:
120 dwCreationDisposition = FILE_CREATE;
121 break;
122
123 case CREATE_ALWAYS:
124 dwCreationDisposition = FILE_OVERWRITE_IF;
125 break;
126
127 case OPEN_EXISTING:
128 dwCreationDisposition = FILE_OPEN;
129 break;
130
131 case OPEN_ALWAYS:
132 dwCreationDisposition = FILE_OPEN_IF;
133 break;
134
135 case TRUNCATE_EXISTING:
136 dwCreationDisposition = FILE_OVERWRITE;
137 break;
138
139 default:
140 SetLastError(ERROR_INVALID_PARAMETER);
141 return (INVALID_HANDLE_VALUE);
142 }
143
144 /* check for console input/output */
145 if (0 == _wcsicmp(L"CONOUT$", lpFileName)
146 || 0 == _wcsicmp(L"CONIN$", lpFileName))
147 {
148 return OpenConsoleW(lpFileName,
149 dwDesiredAccess,
150 lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE,
151 FILE_SHARE_READ | FILE_SHARE_WRITE);
152 }
153
154 /* validate & translate the flags */
155
156 /* translate the flags that need no validation */
157 if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
158 {
159 /* yes, nonalert is correct! apc's are not delivered
160 while waiting for file io to complete */
161 Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
162 }
163
164 if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
165 Flags |= FILE_WRITE_THROUGH;
166
167 if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
168 Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
169
170 if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
171 Flags |= FILE_RANDOM_ACCESS;
172
173 if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
174 Flags |= FILE_SEQUENTIAL_ONLY;
175
176 if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
177 Flags |= FILE_DELETE_ON_CLOSE;
178
179 if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
180 {
181 if(dwDesiredAccess & GENERIC_ALL)
182 Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REMOTE_INSTANCE;
183 else
184 {
185 if(dwDesiredAccess & GENERIC_READ)
186 Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
187
188 if(dwDesiredAccess & GENERIC_WRITE)
189 Flags |= FILE_OPEN_REMOTE_INSTANCE;
190 }
191 }
192 else
193 Flags |= FILE_NON_DIRECTORY_FILE;
194
195 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
196 Flags |= FILE_OPEN_REPARSE_POINT;
197
198 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
199 Flags |= FILE_OPEN_NO_RECALL;
200
201 FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
202
203 /* handle may allways be waited on and querying attributes are allways allowed */
204 dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
205
206 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
207
208 /* validate & translate the filename */
209 if (!RtlDosPathNameToNtPathName_U (lpFileName,
210 &NtPathU,
211 NULL,
212 NULL))
213 {
214 WARN("Invalid path\n");
215 SetLastError(ERROR_FILE_NOT_FOUND);
216 return INVALID_HANDLE_VALUE;
217 }
218
219 TRACE("NtPathU \'%wZ\'\n", &NtPathU);
220
221 if (hTemplateFile != NULL)
222 {
223 FILE_EA_INFORMATION EaInformation;
224
225 for (;;)
226 {
227 /* try to get the size of the extended attributes, if we fail just continue
228 creating the file without copying the attributes! */
229 Status = NtQueryInformationFile(hTemplateFile,
230 &IoStatusBlock,
231 &EaInformation,
232 sizeof(FILE_EA_INFORMATION),
233 FileEaInformation);
234 if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
235 {
236 /* there's extended attributes to read, let's give it a try */
237 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
238 0,
239 EaInformation.EaSize);
240 if (EaBuffer == NULL)
241 {
242 RtlFreeHeap(RtlGetProcessHeap(),
243 0,
244 NtPathU.Buffer);
245
246 /* the template file handle is valid and has extended attributes,
247 however we seem to lack some memory here. We should fail here! */
248 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
249 return INVALID_HANDLE_VALUE;
250 }
251
252 Status = NtQueryEaFile(hTemplateFile,
253 &IoStatusBlock,
254 EaBuffer,
255 EaInformation.EaSize,
256 FALSE,
257 NULL,
258 0,
259 NULL,
260 TRUE);
261
262 if (NT_SUCCESS(Status))
263 {
264 /* we successfully read the extended attributes, break the loop
265 and continue */
266 EaLength = EaInformation.EaSize;
267 break;
268 }
269 else
270 {
271 RtlFreeHeap(RtlGetProcessHeap(),
272 0,
273 EaBuffer);
274 EaBuffer = NULL;
275
276 if (Status != STATUS_BUFFER_TOO_SMALL)
277 {
278 /* unless we just allocated not enough memory, break the loop
279 and just continue without copying extended attributes */
280 break;
281 }
282 }
283 }
284 else
285 {
286 /* we either failed to get the size of the extended attributes or
287 they're empty, just continue as there's no need to copy
288 attributes */
289 break;
290 }
291 }
292 }
293
294 /* build the object attributes */
295 InitializeObjectAttributes(&ObjectAttributes,
296 &NtPathU,
297 0,
298 NULL,
299 NULL);
300
301 if (lpSecurityAttributes)
302 {
303 if(lpSecurityAttributes->bInheritHandle)
304 ObjectAttributes.Attributes |= OBJ_INHERIT;
305
306 ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
307 }
308
309 if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
310 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
311
312 /* perform the call */
313 Status = NtCreateFile (&FileHandle,
314 dwDesiredAccess,
315 &ObjectAttributes,
316 &IoStatusBlock,
317 NULL,
318 FileAttributes,
319 dwShareMode,
320 dwCreationDisposition,
321 Flags,
322 EaBuffer,
323 EaLength);
324
325 RtlFreeHeap(RtlGetProcessHeap(),
326 0,
327 NtPathU.Buffer);
328
329 /* free the extended attributes buffer if allocated */
330 if (EaBuffer != NULL)
331 {
332 RtlFreeHeap(RtlGetProcessHeap(),
333 0,
334 EaBuffer);
335 }
336
337 /* error */
338 if (!NT_SUCCESS(Status))
339 {
340 /* In the case file creation was rejected due to CREATE_NEW flag
341 * was specified and file with that name already exists, correct
342 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
343 * Note: RtlNtStatusToDosError is not the subject to blame here.
344 */
345 if (Status == STATUS_OBJECT_NAME_COLLISION &&
346 dwCreationDisposition == FILE_CREATE)
347 {
348 SetLastError( ERROR_FILE_EXISTS );
349 }
350 else
351 {
352 BaseSetLastNTError (Status);
353 }
354
355 return INVALID_HANDLE_VALUE;
356 }
357
358 /*
359 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
360 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
361 */
362 if (dwCreationDisposition == FILE_OPEN_IF)
363 {
364 SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
365 }
366 else if (dwCreationDisposition == FILE_OVERWRITE_IF)
367 {
368 SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : ERROR_SUCCESS);
369 }
370 else
371 {
372 SetLastError(ERROR_SUCCESS);
373 }
374
375 return FileHandle;
376 }
377
378 /*
379 * @implemented
380 */
381 HFILE WINAPI
382 OpenFile(LPCSTR lpFileName,
383 LPOFSTRUCT lpReOpenBuff,
384 UINT uStyle)
385 {
386 OBJECT_ATTRIBUTES ObjectAttributes;
387 IO_STATUS_BLOCK IoStatusBlock;
388 UNICODE_STRING FileNameString;
389 UNICODE_STRING FileNameU;
390 ANSI_STRING FileName;
391 WCHAR PathNameW[MAX_PATH];
392 HANDLE FileHandle = NULL;
393 NTSTATUS errCode;
394 PWCHAR FilePart;
395 ULONG Len;
396
397 TRACE("OpenFile('%s', lpReOpenBuff %x, uStyle %x)\n", lpFileName, lpReOpenBuff, uStyle);
398
399 if (lpReOpenBuff == NULL)
400 {
401 return HFILE_ERROR;
402 }
403
404 lpReOpenBuff->nErrCode = 0;
405
406 if (uStyle & OF_REOPEN) lpFileName = lpReOpenBuff->szPathName;
407
408 if (!lpFileName)
409 {
410 return HFILE_ERROR;
411 }
412
413 if (!GetFullPathNameA(lpFileName,
414 sizeof(lpReOpenBuff->szPathName),
415 lpReOpenBuff->szPathName,
416 NULL))
417 {
418 lpReOpenBuff->nErrCode = GetLastError();
419 return HFILE_ERROR;
420 }
421
422 if (uStyle & OF_PARSE)
423 {
424 lpReOpenBuff->fFixedDisk = (GetDriveTypeA(lpReOpenBuff->szPathName) != DRIVE_REMOVABLE);
425 TRACE("(%s): OF_PARSE, res = '%s'\n", lpFileName, lpReOpenBuff->szPathName);
426 return 0;
427 }
428
429 if ((uStyle & OF_EXIST) && !(uStyle & OF_CREATE))
430 {
431 DWORD dwAttributes = GetFileAttributesA(lpReOpenBuff->szPathName);
432
433 switch (dwAttributes)
434 {
435 case 0xFFFFFFFF: /* File does not exist */
436 SetLastError(ERROR_FILE_NOT_FOUND);
437 lpReOpenBuff->nErrCode = (WORD) ERROR_FILE_NOT_FOUND;
438 return -1;
439
440 case FILE_ATTRIBUTE_DIRECTORY:
441 SetLastError(ERROR_ACCESS_DENIED);
442 lpReOpenBuff->nErrCode = (WORD) ERROR_ACCESS_DENIED;
443 return -1;
444
445 default:
446 lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
447 return 1;
448 }
449 }
450 lpReOpenBuff->cBytes = sizeof(OFSTRUCT);
451 if ((uStyle & OF_CREATE) == OF_CREATE)
452 {
453 DWORD Sharing;
454 switch (uStyle & 0x70)
455 {
456 case OF_SHARE_EXCLUSIVE: Sharing = 0; break;
457 case OF_SHARE_DENY_WRITE: Sharing = FILE_SHARE_READ; break;
458 case OF_SHARE_DENY_READ: Sharing = FILE_SHARE_WRITE; break;
459 case OF_SHARE_DENY_NONE:
460 case OF_SHARE_COMPAT:
461 default:
462 Sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
463 }
464 return (HFILE) CreateFileA (lpFileName,
465 GENERIC_READ | GENERIC_WRITE,
466 Sharing,
467 NULL,
468 CREATE_ALWAYS,
469 FILE_ATTRIBUTE_NORMAL,
470 0);
471 }
472
473 RtlInitAnsiString (&FileName, (LPSTR)lpFileName);
474
475 /* convert ansi (or oem) string to unicode */
476 if (bIsFileApiAnsi)
477 RtlAnsiStringToUnicodeString (&FileNameU, &FileName, TRUE);
478 else
479 RtlOemStringToUnicodeString (&FileNameU, &FileName, TRUE);
480
481 Len = SearchPathW (NULL,
482 FileNameU.Buffer,
483 NULL,
484 OFS_MAXPATHNAME,
485 PathNameW,
486 &FilePart);
487
488 RtlFreeUnicodeString(&FileNameU);
489
490 if (Len == 0 || Len > OFS_MAXPATHNAME)
491 {
492 lpReOpenBuff->nErrCode = GetLastError();
493 return (HFILE)INVALID_HANDLE_VALUE;
494 }
495
496 if (uStyle & OF_DELETE)
497 {
498 if (!DeleteFileW(PathNameW))
499 {
500 lpReOpenBuff->nErrCode = GetLastError();
501 return HFILE_ERROR;
502 }
503 TRACE("(%s): OF_DELETE return = OK\n", lpFileName);
504 return TRUE;
505 }
506
507 FileName.Buffer = lpReOpenBuff->szPathName;
508 FileName.Length = 0;
509 FileName.MaximumLength = OFS_MAXPATHNAME;
510
511 RtlInitUnicodeString(&FileNameU, PathNameW);
512
513 /* convert unicode string to ansi (or oem) */
514 if (bIsFileApiAnsi)
515 RtlUnicodeStringToAnsiString (&FileName, &FileNameU, FALSE);
516 else
517 RtlUnicodeStringToOemString (&FileName, &FileNameU, FALSE);
518
519 if (!RtlDosPathNameToNtPathName_U (PathNameW,
520 &FileNameString,
521 NULL,
522 NULL))
523 {
524 return (HFILE)INVALID_HANDLE_VALUE;
525 }
526
527 // FILE_SHARE_READ
528 // FILE_NO_INTERMEDIATE_BUFFERING
529
530 ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
531 ObjectAttributes.RootDirectory = NULL;
532 ObjectAttributes.ObjectName = &FileNameString;
533 ObjectAttributes.Attributes = OBJ_CASE_INSENSITIVE| OBJ_INHERIT;
534 ObjectAttributes.SecurityDescriptor = NULL;
535 ObjectAttributes.SecurityQualityOfService = NULL;
536
537 errCode = NtOpenFile (&FileHandle,
538 GENERIC_READ|SYNCHRONIZE,
539 &ObjectAttributes,
540 &IoStatusBlock,
541 FILE_SHARE_READ,
542 FILE_NON_DIRECTORY_FILE|FILE_SYNCHRONOUS_IO_NONALERT);
543
544 RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameString.Buffer);
545
546 lpReOpenBuff->nErrCode = RtlNtStatusToDosError(errCode);
547
548 if (!NT_SUCCESS(errCode))
549 {
550 BaseSetLastNTError (errCode);
551 return (HFILE)INVALID_HANDLE_VALUE;
552 }
553
554 if (uStyle & OF_EXIST)
555 {
556 NtClose(FileHandle);
557 return (HFILE)1;
558 }
559
560 return (HFILE)FileHandle;
561 }
562
563 /*
564 * @unimplemented
565 */
566 BOOL
567 WINAPI
568 OpenDataFile(HANDLE hFile, DWORD dwUnused)
569 {
570 STUB;
571 return FALSE;
572 }
573
574 /*
575 * @unimplemented
576 */
577 HANDLE
578 WINAPI
579 ReOpenFile(IN HANDLE hOriginalFile,
580 IN DWORD dwDesiredAccess,
581 IN DWORD dwShareMode,
582 IN DWORD dwFlags)
583 {
584 STUB;
585 return INVALID_HANDLE_VALUE;
586 }
587
588 /* EOF */