d80b479bab5b7eaed51e1286a3c528f4edc0f1d5
[reactos.git] / reactos / lib / kernel32 / file / create.c
1 /* $Id$
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 * GetTempFileName is modified from WINE [ Alexandre Juiliard ]
9 * UPDATE HISTORY:
10 * Created 01/11/98
11 * Removed use of SearchPath (not used by Windows)
12 * 18/08/2002: CreateFileW mess cleaned up (KJK::Hyperion)
13 * 24/08/2002: removed superfluous DPRINTs (KJK::Hyperion)
14 */
15
16 /* INCLUDES *****************************************************************/
17
18 #include <k32.h>
19
20 #define NDEBUG
21 #include "../include/debug.h"
22
23
24 /* FUNCTIONS ****************************************************************/
25
26 /*
27 * @implemented
28 */
29 HANDLE STDCALL 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 DPRINT("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 STDCALL 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 HANDLE FileHandle;
72 NTSTATUS Status;
73 ULONG FileAttributes, Flags = 0;
74 CSR_API_MESSAGE Request;
75 PVOID EaBuffer = NULL;
76 ULONG EaLength = 0;
77
78 DPRINT("CreateFileW(lpFileName %S)\n",lpFileName);
79
80 /* validate & translate the creation disposition */
81 switch (dwCreationDisposition)
82 {
83 case CREATE_NEW:
84 dwCreationDisposition = FILE_CREATE;
85 break;
86
87 case CREATE_ALWAYS:
88 dwCreationDisposition = FILE_OVERWRITE_IF;
89 break;
90
91 case OPEN_EXISTING:
92 dwCreationDisposition = FILE_OPEN;
93 break;
94
95 case OPEN_ALWAYS:
96 dwCreationDisposition = FILE_OPEN_IF;
97 break;
98
99 case TRUNCATE_EXISTING:
100 dwCreationDisposition = FILE_OVERWRITE;
101 break;
102
103 default:
104 SetLastError(ERROR_INVALID_PARAMETER);
105 return (INVALID_HANDLE_VALUE);
106 }
107
108 /* validate & translate the filename */
109 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
110 &NtPathU,
111 NULL,
112 NULL))
113 {
114 DPRINT("Invalid path\n");
115 SetLastError(ERROR_PATH_NOT_FOUND);
116 return INVALID_HANDLE_VALUE;
117 }
118
119 DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
120
121 /* validate & translate the flags */
122
123 /* translate the flags that need no validation */
124 if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
125 {
126 /* yes, nonalert is correct! apc's are not delivered
127 while waiting for file io to complete */
128 Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
129 }
130
131 if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
132 Flags |= FILE_WRITE_THROUGH;
133
134 if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
135 Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
136
137 if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
138 Flags |= FILE_RANDOM_ACCESS;
139
140 if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
141 Flags |= FILE_SEQUENTIAL_ONLY;
142
143 if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
144 Flags |= FILE_DELETE_ON_CLOSE;
145
146 if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
147 {
148 if(dwDesiredAccess & GENERIC_ALL)
149 Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
150 else
151 {
152 if(dwDesiredAccess & GENERIC_READ)
153 Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
154
155 if(dwDesiredAccess & GENERIC_WRITE)
156 Flags |= FILE_OPEN_FOR_RECOVERY;
157 }
158 }
159 else
160 Flags |= FILE_NON_DIRECTORY_FILE;
161
162 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
163 Flags |= FILE_OPEN_REPARSE_POINT;
164
165 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
166 Flags |= FILE_OPEN_NO_RECALL;
167
168 FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
169
170 /* handle may allways be waited on and querying attributes are allways allowed */
171 dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
172
173 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
174
175 /* check for console output */
176 if (0 == _wcsicmp(L"CONOUT$", lpFileName))
177 {
178 /* FIXME: Send required access rights to Csrss */
179 Status = CsrClientCallServer(&Request,
180 NULL,
181 MAKE_CSR_API(GET_OUTPUT_HANDLE, CSR_NATIVE),
182 sizeof(CSR_API_MESSAGE));
183 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
184 {
185 SetLastErrorByStatus(Status);
186 return INVALID_HANDLE_VALUE;
187 }
188 else
189 {
190 return Request.Data.GetOutputHandleRequest.OutputHandle;
191 }
192 }
193
194 /* check for console input */
195 if (0 == _wcsicmp(L"CONIN$", lpFileName))
196 {
197 /* FIXME: Send required access rights to Csrss */
198 Status = CsrClientCallServer(&Request,
199 NULL,
200 MAKE_CSR_API(GET_INPUT_HANDLE, CSR_NATIVE),
201 sizeof(CSR_API_MESSAGE));
202 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Request.Status))
203 {
204 SetLastErrorByStatus(Status);
205 return INVALID_HANDLE_VALUE;
206 }
207 else
208 {
209 return Request.Data.GetInputHandleRequest.InputHandle;
210 }
211 }
212
213 if (hTemplateFile != NULL)
214 {
215 FILE_EA_INFORMATION EaInformation;
216
217 for (;;)
218 {
219 /* try to get the size of the extended attributes, if we fail just continue
220 creating the file without copying the attributes! */
221 Status = NtQueryInformationFile(hTemplateFile,
222 &IoStatusBlock,
223 &EaInformation,
224 sizeof(FILE_EA_INFORMATION),
225 FileEaInformation);
226 if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
227 {
228 /* there's extended attributes to read, let's give it a try */
229 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
230 0,
231 EaInformation.EaSize);
232 if (EaBuffer == NULL)
233 {
234 /* the template file handle is valid and has extended attributes,
235 however we seem to lack some memory here. We should fail here! */
236 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
237 return INVALID_HANDLE_VALUE;
238 }
239
240 Status = NtQueryEaFile(hTemplateFile,
241 &IoStatusBlock,
242 EaBuffer,
243 EaInformation.EaSize,
244 FALSE,
245 NULL,
246 0,
247 NULL,
248 TRUE);
249
250 if (NT_SUCCESS(Status))
251 {
252 /* we successfully read the extended attributes, break the loop
253 and continue */
254 EaLength = EaInformation.EaSize;
255 break;
256 }
257 else
258 {
259 RtlFreeHeap(RtlGetProcessHeap(),
260 0,
261 EaBuffer);
262 EaBuffer = NULL;
263
264 if (Status != STATUS_BUFFER_TOO_SMALL)
265 {
266 /* unless we just allocated not enough memory, break the loop
267 and just continue without copying extended attributes */
268 break;
269 }
270 }
271 }
272 else
273 {
274 /* we either failed to get the size of the extended attributes or
275 they're empty, just continue as there's no need to copy
276 attributes */
277 break;
278 }
279 }
280 }
281
282 /* build the object attributes */
283 InitializeObjectAttributes(&ObjectAttributes,
284 &NtPathU,
285 0,
286 NULL,
287 NULL);
288
289 if (lpSecurityAttributes)
290 {
291 if(lpSecurityAttributes->bInheritHandle)
292 ObjectAttributes.Attributes |= OBJ_INHERIT;
293
294 ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
295 }
296
297 if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
298 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
299
300 /* perform the call */
301 Status = NtCreateFile (&FileHandle,
302 dwDesiredAccess,
303 &ObjectAttributes,
304 &IoStatusBlock,
305 NULL,
306 FileAttributes,
307 dwShareMode,
308 dwCreationDisposition,
309 Flags,
310 EaBuffer,
311 EaLength);
312
313 RtlFreeUnicodeString(&NtPathU);
314
315 /* free the extended attributes buffer if allocated */
316 if (EaBuffer != NULL)
317 {
318 RtlFreeHeap(RtlGetProcessHeap(),
319 0,
320 EaBuffer);
321 }
322
323 /* error */
324 if (!NT_SUCCESS(Status))
325 {
326 /* In the case file creation was rejected due to CREATE_NEW flag
327 * was specified and file with that name already exists, correct
328 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
329 * Note: RtlNtStatusToDosError is not the subject to blame here.
330 */
331 if (Status == STATUS_OBJECT_NAME_COLLISION &&
332 dwCreationDisposition == FILE_CREATE)
333 {
334 SetLastError( ERROR_FILE_EXISTS );
335 }
336 else
337 {
338 SetLastErrorByStatus (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 : 0);
351 }
352 else if (dwCreationDisposition == FILE_OVERWRITE_IF)
353 {
354 SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
355 }
356
357 return FileHandle;
358 }
359
360 /* EOF */