xref: /reactos/dll/win32/kernel32/client/file/create.c (revision 5391eaad)
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  */
CreateFileA(LPCSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)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  */
CreateFileW(LPCWSTR lpFileName,DWORD dwDesiredAccess,DWORD dwShareMode,LPSECURITY_ATTRIBUTES lpSecurityAttributes,DWORD dwCreationDisposition,DWORD dwFlagsAndAttributes,HANDLE hTemplateFile)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
OpenFile(LPCSTR lpFileName,LPOFSTRUCT lpReOpenBuff,UINT uStyle)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)(ULONG_PTR) 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_ERROR;
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_ERROR;
511 	}
512 
513 	// FILE_SHARE_READ
514 	// FILE_NO_INTERMEDIATE_BUFFERING
515 
516     InitializeObjectAttributes(&ObjectAttributes,
517                                &FileNameString,
518                                OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
519                                NULL,
520                                NULL);
521 
522 	errCode = NtOpenFile (&FileHandle,
523 	                      GENERIC_READ | SYNCHRONIZE,
524 	                      &ObjectAttributes,
525 	                      &IoStatusBlock,
526 	                      FILE_SHARE_READ,
527 	                      FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
528 
529 	RtlFreeHeap(RtlGetProcessHeap(), 0, FileNameString.Buffer);
530 
531 	lpReOpenBuff->nErrCode = (WORD)RtlNtStatusToDosError(errCode);
532 
533 	if (!NT_SUCCESS(errCode))
534 	{
535 		BaseSetLastNTError (errCode);
536 		return HFILE_ERROR;
537 	}
538 
539 	if (uStyle & OF_EXIST)
540 	{
541 		NtClose(FileHandle);
542 		return (HFILE)1;
543 	}
544 
545 	return (HFILE)(ULONG_PTR)FileHandle;
546 }
547 
548 /*
549  * @unimplemented
550  */
551 BOOL
552 WINAPI
OpenDataFile(HANDLE hFile,DWORD dwUnused)553 OpenDataFile(HANDLE hFile, DWORD dwUnused)
554 {
555     STUB;
556     return FALSE;
557 }
558 
559 /*
560  * @unimplemented
561  */
562 HANDLE
563 WINAPI
ReOpenFile(IN HANDLE hOriginalFile,IN DWORD dwDesiredAccess,IN DWORD dwShareMode,IN DWORD dwFlags)564 ReOpenFile(IN HANDLE hOriginalFile,
565            IN DWORD dwDesiredAccess,
566            IN DWORD dwShareMode,
567            IN DWORD dwFlags)
568 {
569    STUB;
570    return INVALID_HANDLE_VALUE;
571 }
572 
573 /* EOF */
574