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