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