added support for template directories (copy ntfs extended attributes) to CreateDirec...
[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 UNICODE_STRING FileNameU;
38 ANSI_STRING FileName;
39 HANDLE FileHandle;
40
41 DPRINT("CreateFileA(lpFileName %s)\n",lpFileName);
42
43 RtlInitAnsiString (&FileName,
44 (LPSTR)lpFileName);
45
46 /* convert ansi (or oem) string to unicode */
47 if (bIsFileApiAnsi)
48 RtlAnsiStringToUnicodeString (&FileNameU,
49 &FileName,
50 TRUE);
51 else
52 RtlOemStringToUnicodeString (&FileNameU,
53 &FileName,
54 TRUE);
55
56 FileHandle = CreateFileW (FileNameU.Buffer,
57 dwDesiredAccess,
58 dwShareMode,
59 lpSecurityAttributes,
60 dwCreationDisposition,
61 dwFlagsAndAttributes,
62 hTemplateFile);
63
64 RtlFreeHeap (RtlGetProcessHeap (),
65 0,
66 FileNameU.Buffer);
67
68 return FileHandle;
69 }
70
71
72 /*
73 * @implemented
74 */
75 HANDLE STDCALL CreateFileW (LPCWSTR lpFileName,
76 DWORD dwDesiredAccess,
77 DWORD dwShareMode,
78 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
79 DWORD dwCreationDisposition,
80 DWORD dwFlagsAndAttributes,
81 HANDLE hTemplateFile)
82 {
83 OBJECT_ATTRIBUTES ObjectAttributes;
84 IO_STATUS_BLOCK IoStatusBlock;
85 UNICODE_STRING NtPathU;
86 HANDLE FileHandle;
87 NTSTATUS Status;
88 ULONG FileAttributes, Flags = 0;
89 CSRSS_API_REQUEST Request;
90 CSRSS_API_REPLY Reply;
91 PVOID EaBuffer = NULL;
92 ULONG EaLength = 0;
93
94 DPRINT("CreateFileW(lpFileName %S)\n",lpFileName);
95
96 /* validate & translate the creation disposition */
97 switch (dwCreationDisposition)
98 {
99 case CREATE_NEW:
100 dwCreationDisposition = FILE_CREATE;
101 break;
102
103 case CREATE_ALWAYS:
104 dwCreationDisposition = FILE_OVERWRITE_IF;
105 break;
106
107 case OPEN_EXISTING:
108 dwCreationDisposition = FILE_OPEN;
109 break;
110
111 case OPEN_ALWAYS:
112 dwCreationDisposition = FILE_OPEN_IF;
113 break;
114
115 case TRUNCATE_EXISTING:
116 dwCreationDisposition = FILE_OVERWRITE;
117 break;
118
119 default:
120 SetLastError(ERROR_INVALID_PARAMETER);
121 return (INVALID_HANDLE_VALUE);
122 }
123
124 /* validate & translate the filename */
125 if (!RtlDosPathNameToNtPathName_U ((LPWSTR)lpFileName,
126 &NtPathU,
127 NULL,
128 NULL))
129 {
130 DPRINT("Invalid path\n");
131 SetLastError(ERROR_PATH_NOT_FOUND);
132 return INVALID_HANDLE_VALUE;
133 }
134
135 DPRINT("NtPathU \'%S\'\n", NtPathU.Buffer);
136
137 /* validate & translate the flags */
138
139 /* translate the flags that need no validation */
140 if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
141 {
142 /* yes, nonalert is correct! apc's are not delivered
143 while waiting for file io to complete */
144 Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
145 }
146
147 if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
148 Flags |= FILE_WRITE_THROUGH;
149
150 if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
151 Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
152
153 if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
154 Flags |= FILE_RANDOM_ACCESS;
155
156 if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
157 Flags |= FILE_SEQUENTIAL_ONLY;
158
159 if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
160 Flags |= FILE_DELETE_ON_CLOSE;
161
162 if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
163 {
164 if(dwDesiredAccess & GENERIC_ALL)
165 Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_FOR_RECOVERY;
166 else
167 {
168 if(dwDesiredAccess & GENERIC_READ)
169 Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
170
171 if(dwDesiredAccess & GENERIC_WRITE)
172 Flags |= FILE_OPEN_FOR_RECOVERY;
173 }
174 }
175 else
176 Flags |= FILE_NON_DIRECTORY_FILE;
177
178 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
179 Flags |= FILE_OPEN_REPARSE_POINT;
180
181 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
182 Flags |= FILE_OPEN_NO_RECALL;
183
184 FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
185
186 /* handle may allways be waited on and querying attributes are allways allowed */
187 dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
188
189 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
190
191 /* check for console output */
192 if (0 == _wcsicmp(L"CONOUT$", lpFileName))
193 {
194 /* FIXME: Send required access rights to Csrss */
195 Request.Type = CSRSS_GET_OUTPUT_HANDLE;
196 Status = CsrClientCallServer(&Request,
197 &Reply,
198 sizeof(CSRSS_API_REQUEST),
199 sizeof(CSRSS_API_REPLY));
200 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
201 {
202 SetLastErrorByStatus(Status);
203 return INVALID_HANDLE_VALUE;
204 }
205 else
206 {
207 return Reply.Data.GetOutputHandleReply.OutputHandle;
208 }
209 }
210
211 /* check for console input */
212 if (0 == _wcsicmp(L"CONIN$", lpFileName))
213 {
214 /* FIXME: Send required access rights to Csrss */
215 Request.Type = CSRSS_GET_INPUT_HANDLE;
216 Status = CsrClientCallServer(&Request,
217 &Reply,
218 sizeof(CSRSS_API_REQUEST),
219 sizeof(CSRSS_API_REPLY));
220 if (!NT_SUCCESS(Status) || !NT_SUCCESS(Status = Reply.Status))
221 {
222 SetLastErrorByStatus(Status);
223 return INVALID_HANDLE_VALUE;
224 }
225 else
226 {
227 return Reply.Data.GetInputHandleReply.InputHandle;
228 }
229 }
230
231 if (hTemplateFile != NULL)
232 {
233 FILE_EA_INFORMATION EaInformation;
234
235 for (;;)
236 {
237 /* try to get the size of the extended attributes, if we fail just continue
238 creating the file without copying the attributes! */
239 Status = NtQueryInformationFile(hTemplateFile,
240 &IoStatusBlock,
241 &EaInformation,
242 sizeof(FILE_EA_INFORMATION),
243 FileEaInformation);
244 if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
245 {
246 /* there's extended attributes to read, let's give it a try */
247 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
248 0,
249 EaInformation.EaSize);
250 if (EaBuffer == NULL)
251 {
252 /* the template file handle is valid and has extended attributes,
253 however we seem to lack some memory here. We should fail here! */
254 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
255 return INVALID_HANDLE_VALUE;
256 }
257
258 Status = NtQueryEaFile(hTemplateFile,
259 &IoStatusBlock,
260 EaBuffer,
261 EaInformation.EaSize,
262 FALSE,
263 NULL,
264 0,
265 NULL,
266 TRUE);
267
268 if (NT_SUCCESS(Status))
269 {
270 /* we successfully read the extended attributes, break the loop
271 and continue */
272 EaLength = EaInformation.EaSize;
273 break;
274 }
275 else
276 {
277 RtlFreeHeap(RtlGetProcessHeap(),
278 0,
279 EaBuffer);
280 EaBuffer = NULL;
281
282 if (Status != STATUS_BUFFER_TOO_SMALL)
283 {
284 /* unless we just allocated not enough memory, break the loop
285 and just continue without copying extended attributes */
286 break;
287 }
288 }
289 }
290 else
291 {
292 /* we either failed to get the size of the extended attributes or
293 they're empty, just continue as there's no need to copy
294 attributes */
295 break;
296 }
297 }
298 }
299
300 /* build the object attributes */
301 InitializeObjectAttributes(&ObjectAttributes,
302 &NtPathU,
303 0,
304 NULL,
305 NULL);
306
307 if (lpSecurityAttributes)
308 {
309 if(lpSecurityAttributes->bInheritHandle)
310 ObjectAttributes.Attributes |= OBJ_INHERIT;
311
312 ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
313 }
314
315 if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
316 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
317
318 /* perform the call */
319 Status = NtCreateFile (&FileHandle,
320 dwDesiredAccess,
321 &ObjectAttributes,
322 &IoStatusBlock,
323 NULL,
324 FileAttributes,
325 dwShareMode,
326 dwCreationDisposition,
327 Flags,
328 EaBuffer,
329 EaLength);
330
331 RtlFreeUnicodeString(&NtPathU);
332
333 /* free the extended attributes buffer if allocated */
334 if (EaBuffer != NULL)
335 {
336 RtlFreeHeap(RtlGetProcessHeap(),
337 0,
338 EaBuffer);
339 }
340
341 /* error */
342 if (!NT_SUCCESS(Status))
343 {
344 /* In the case file creation was rejected due to CREATE_NEW flag
345 * was specified and file with that name already exists, correct
346 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
347 * Note: RtlNtStatusToDosError is not the subject to blame here.
348 */
349 if (Status == STATUS_OBJECT_NAME_COLLISION &&
350 dwCreationDisposition == FILE_CREATE)
351 {
352 SetLastError( ERROR_FILE_EXISTS );
353 }
354 else
355 {
356 SetLastErrorByStatus (Status);
357 }
358
359 return INVALID_HANDLE_VALUE;
360 }
361
362 /*
363 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
364 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
365 */
366 if (dwCreationDisposition == FILE_OPEN_IF)
367 {
368 SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
369 }
370 else if (dwCreationDisposition == FILE_OVERWRITE_IF)
371 {
372 SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
373 }
374
375 return FileHandle;
376 }
377
378 /* EOF */