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