- Update to r53061
[reactos.git] / dll / win32 / kernel32 / client / 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 * UPDATE HISTORY:
9 * Created 01/11/98
10 * Removed use of SearchPath (not used by Windows)
11 * 18/08/2002: CreateFileW mess cleaned up (KJK::Hyperion)
12 * 24/08/2002: removed superfluous DPRINTs (KJK::Hyperion)
13 */
14
15 /* INCLUDES *****************************************************************/
16
17 #include <k32.h>
18 #define NDEBUG
19 #include <debug.h>
20
21 #if DBG
22 DEBUG_CHANNEL(kernel32file);
23 #endif
24
25 #define SYMLINK_FLAG_RELATIVE 1
26
27 typedef struct _REPARSE_DATA_BUFFER {
28 ULONG ReparseTag;
29 USHORT ReparseDataLength;
30 USHORT Reserved;
31 union {
32 struct {
33 USHORT SubstituteNameOffset;
34 USHORT SubstituteNameLength;
35 USHORT PrintNameOffset;
36 USHORT PrintNameLength;
37 ULONG Flags;
38 WCHAR PathBuffer[1];
39 } SymbolicLinkReparseBuffer;
40 struct {
41 USHORT SubstituteNameOffset;
42 USHORT SubstituteNameLength;
43 USHORT PrintNameOffset;
44 USHORT PrintNameLength;
45 WCHAR PathBuffer[1];
46 } MountPointReparseBuffer;
47 struct {
48 UCHAR DataBuffer[1];
49 } GenericReparseBuffer;
50 };
51 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
52
53 #define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
54
55 /* FUNCTIONS ****************************************************************/
56
57 /*
58 * @implemented
59 */
60 HANDLE WINAPI CreateFileA (LPCSTR lpFileName,
61 DWORD dwDesiredAccess,
62 DWORD dwShareMode,
63 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
64 DWORD dwCreationDisposition,
65 DWORD dwFlagsAndAttributes,
66 HANDLE hTemplateFile)
67 {
68 PWCHAR FileNameW;
69 HANDLE FileHandle;
70
71 TRACE("CreateFileA(lpFileName %s)\n",lpFileName);
72
73 if (!(FileNameW = FilenameA2W(lpFileName, FALSE)))
74 return INVALID_HANDLE_VALUE;
75
76 FileHandle = CreateFileW (FileNameW,
77 dwDesiredAccess,
78 dwShareMode,
79 lpSecurityAttributes,
80 dwCreationDisposition,
81 dwFlagsAndAttributes,
82 hTemplateFile);
83
84 return FileHandle;
85 }
86
87
88 /*
89 * @implemented
90 */
91 HANDLE WINAPI CreateFileW (LPCWSTR lpFileName,
92 DWORD dwDesiredAccess,
93 DWORD dwShareMode,
94 LPSECURITY_ATTRIBUTES lpSecurityAttributes,
95 DWORD dwCreationDisposition,
96 DWORD dwFlagsAndAttributes,
97 HANDLE hTemplateFile)
98 {
99 OBJECT_ATTRIBUTES ObjectAttributes;
100 IO_STATUS_BLOCK IoStatusBlock;
101 UNICODE_STRING NtPathU;
102 HANDLE FileHandle;
103 NTSTATUS Status;
104 ULONG FileAttributes, Flags = 0;
105 PVOID EaBuffer = NULL;
106 ULONG EaLength = 0;
107
108 if (!lpFileName || !lpFileName[0])
109 {
110 SetLastError( ERROR_PATH_NOT_FOUND );
111 return INVALID_HANDLE_VALUE;
112 }
113
114 TRACE("CreateFileW(lpFileName %S)\n",lpFileName);
115
116 /* validate & translate the creation disposition */
117 switch (dwCreationDisposition)
118 {
119 case CREATE_NEW:
120 dwCreationDisposition = FILE_CREATE;
121 break;
122
123 case CREATE_ALWAYS:
124 dwCreationDisposition = FILE_OVERWRITE_IF;
125 break;
126
127 case OPEN_EXISTING:
128 dwCreationDisposition = FILE_OPEN;
129 break;
130
131 case OPEN_ALWAYS:
132 dwCreationDisposition = FILE_OPEN_IF;
133 break;
134
135 case TRUNCATE_EXISTING:
136 dwCreationDisposition = FILE_OVERWRITE;
137 break;
138
139 default:
140 SetLastError(ERROR_INVALID_PARAMETER);
141 return (INVALID_HANDLE_VALUE);
142 }
143
144 /* check for console input/output */
145 if (0 == _wcsicmp(L"CONOUT$", lpFileName)
146 || 0 == _wcsicmp(L"CONIN$", lpFileName))
147 {
148 return OpenConsoleW(lpFileName,
149 dwDesiredAccess,
150 lpSecurityAttributes ? lpSecurityAttributes->bInheritHandle : FALSE,
151 FILE_SHARE_READ | FILE_SHARE_WRITE);
152 }
153
154 /* validate & translate the flags */
155
156 /* translate the flags that need no validation */
157 if (!(dwFlagsAndAttributes & FILE_FLAG_OVERLAPPED))
158 {
159 /* yes, nonalert is correct! apc's are not delivered
160 while waiting for file io to complete */
161 Flags |= FILE_SYNCHRONOUS_IO_NONALERT;
162 }
163
164 if(dwFlagsAndAttributes & FILE_FLAG_WRITE_THROUGH)
165 Flags |= FILE_WRITE_THROUGH;
166
167 if(dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING)
168 Flags |= FILE_NO_INTERMEDIATE_BUFFERING;
169
170 if(dwFlagsAndAttributes & FILE_FLAG_RANDOM_ACCESS)
171 Flags |= FILE_RANDOM_ACCESS;
172
173 if(dwFlagsAndAttributes & FILE_FLAG_SEQUENTIAL_SCAN)
174 Flags |= FILE_SEQUENTIAL_ONLY;
175
176 if(dwFlagsAndAttributes & FILE_FLAG_DELETE_ON_CLOSE)
177 Flags |= FILE_DELETE_ON_CLOSE;
178
179 if(dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
180 {
181 if(dwDesiredAccess & GENERIC_ALL)
182 Flags |= FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REMOTE_INSTANCE;
183 else
184 {
185 if(dwDesiredAccess & GENERIC_READ)
186 Flags |= FILE_OPEN_FOR_BACKUP_INTENT;
187
188 if(dwDesiredAccess & GENERIC_WRITE)
189 Flags |= FILE_OPEN_REMOTE_INSTANCE;
190 }
191 }
192 else
193 Flags |= FILE_NON_DIRECTORY_FILE;
194
195 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_REPARSE_POINT)
196 Flags |= FILE_OPEN_REPARSE_POINT;
197
198 if(dwFlagsAndAttributes & FILE_FLAG_OPEN_NO_RECALL)
199 Flags |= FILE_OPEN_NO_RECALL;
200
201 FileAttributes = (dwFlagsAndAttributes & (FILE_ATTRIBUTE_VALID_FLAGS & ~FILE_ATTRIBUTE_DIRECTORY));
202
203 /* handle may allways be waited on and querying attributes are allways allowed */
204 dwDesiredAccess |= SYNCHRONIZE | FILE_READ_ATTRIBUTES;
205
206 /* FILE_FLAG_POSIX_SEMANTICS is handled later */
207
208 /* validate & translate the filename */
209 if (!RtlDosPathNameToNtPathName_U (lpFileName,
210 &NtPathU,
211 NULL,
212 NULL))
213 {
214 WARN("Invalid path\n");
215 SetLastError(ERROR_PATH_NOT_FOUND);
216 return INVALID_HANDLE_VALUE;
217 }
218
219 TRACE("NtPathU \'%wZ\'\n", &NtPathU);
220
221 if (hTemplateFile != NULL)
222 {
223 FILE_EA_INFORMATION EaInformation;
224
225 for (;;)
226 {
227 /* try to get the size of the extended attributes, if we fail just continue
228 creating the file without copying the attributes! */
229 Status = NtQueryInformationFile(hTemplateFile,
230 &IoStatusBlock,
231 &EaInformation,
232 sizeof(FILE_EA_INFORMATION),
233 FileEaInformation);
234 if (NT_SUCCESS(Status) && (EaInformation.EaSize != 0))
235 {
236 /* there's extended attributes to read, let's give it a try */
237 EaBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
238 0,
239 EaInformation.EaSize);
240 if (EaBuffer == NULL)
241 {
242 RtlFreeHeap(RtlGetProcessHeap(),
243 0,
244 NtPathU.Buffer);
245
246 /* the template file handle is valid and has extended attributes,
247 however we seem to lack some memory here. We should fail here! */
248 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
249 return INVALID_HANDLE_VALUE;
250 }
251
252 Status = NtQueryEaFile(hTemplateFile,
253 &IoStatusBlock,
254 EaBuffer,
255 EaInformation.EaSize,
256 FALSE,
257 NULL,
258 0,
259 NULL,
260 TRUE);
261
262 if (NT_SUCCESS(Status))
263 {
264 /* we successfully read the extended attributes, break the loop
265 and continue */
266 EaLength = EaInformation.EaSize;
267 break;
268 }
269 else
270 {
271 RtlFreeHeap(RtlGetProcessHeap(),
272 0,
273 EaBuffer);
274 EaBuffer = NULL;
275
276 if (Status != STATUS_BUFFER_TOO_SMALL)
277 {
278 /* unless we just allocated not enough memory, break the loop
279 and just continue without copying extended attributes */
280 break;
281 }
282 }
283 }
284 else
285 {
286 /* we either failed to get the size of the extended attributes or
287 they're empty, just continue as there's no need to copy
288 attributes */
289 break;
290 }
291 }
292 }
293
294 /* build the object attributes */
295 InitializeObjectAttributes(&ObjectAttributes,
296 &NtPathU,
297 0,
298 NULL,
299 NULL);
300
301 if (lpSecurityAttributes)
302 {
303 if(lpSecurityAttributes->bInheritHandle)
304 ObjectAttributes.Attributes |= OBJ_INHERIT;
305
306 ObjectAttributes.SecurityDescriptor = lpSecurityAttributes->lpSecurityDescriptor;
307 }
308
309 if(!(dwFlagsAndAttributes & FILE_FLAG_POSIX_SEMANTICS))
310 ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;
311
312 /* perform the call */
313 Status = NtCreateFile (&FileHandle,
314 dwDesiredAccess,
315 &ObjectAttributes,
316 &IoStatusBlock,
317 NULL,
318 FileAttributes,
319 dwShareMode,
320 dwCreationDisposition,
321 Flags,
322 EaBuffer,
323 EaLength);
324
325 RtlFreeHeap(RtlGetProcessHeap(),
326 0,
327 NtPathU.Buffer);
328
329 /* free the extended attributes buffer if allocated */
330 if (EaBuffer != NULL)
331 {
332 RtlFreeHeap(RtlGetProcessHeap(),
333 0,
334 EaBuffer);
335 }
336
337 /* error */
338 if (!NT_SUCCESS(Status))
339 {
340 /* In the case file creation was rejected due to CREATE_NEW flag
341 * was specified and file with that name already exists, correct
342 * last error is ERROR_FILE_EXISTS and not ERROR_ALREADY_EXISTS.
343 * Note: RtlNtStatusToDosError is not the subject to blame here.
344 */
345 if (Status == STATUS_OBJECT_NAME_COLLISION &&
346 dwCreationDisposition == FILE_CREATE)
347 {
348 SetLastError( ERROR_FILE_EXISTS );
349 }
350 else
351 {
352 BaseSetLastNTError (Status);
353 }
354
355 return INVALID_HANDLE_VALUE;
356 }
357
358 /*
359 create with OPEN_ALWAYS (FILE_OPEN_IF) returns info = FILE_OPENED or FILE_CREATED
360 create with CREATE_ALWAYS (FILE_OVERWRITE_IF) returns info = FILE_OVERWRITTEN or FILE_CREATED
361 */
362 if (dwCreationDisposition == FILE_OPEN_IF)
363 {
364 SetLastError(IoStatusBlock.Information == FILE_OPENED ? ERROR_ALREADY_EXISTS : 0);
365 }
366 else if (dwCreationDisposition == FILE_OVERWRITE_IF)
367 {
368 SetLastError(IoStatusBlock.Information == FILE_OVERWRITTEN ? ERROR_ALREADY_EXISTS : 0);
369 }
370
371 return FileHandle;
372 }
373
374 /* EOF */