ef1ef3ccd88473fb9dd61f20844921b850c96ac8
[reactos.git] / reactos / ntoskrnl / io / create.c
1 /* $Id: create.c,v 1.74 2004/08/15 16:39:03 chorns Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/create.c
6 * PURPOSE: Handling file create/open apis
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * 24/05/98: Created
10 */
11
12 /* INCLUDES ***************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 #define TAG_FILE_NAME TAG('F', 'N', 'A', 'M')
21
22 /* FUNCTIONS *************************************************************/
23
24 /**********************************************************************
25 * NAME EXPORTED
26 * NtDeleteFile@4
27 *
28 * DESCRIPTION
29 *
30 * ARGUMENTS
31 * ObjectAttributes
32 * ?
33 *
34 * RETURN VALUE
35 *
36 * REVISIONS
37 *
38 * @unimplemented
39 */
40 NTSTATUS STDCALL
41 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
42 {
43 UNIMPLEMENTED;
44 return(STATUS_NOT_IMPLEMENTED);
45 }
46
47
48 /**********************************************************************
49 * NAME INTERNAL
50 * IopCreateFile
51 *
52 * DESCRIPTION
53 *
54 * ARGUMENTS
55 *
56 * RETURN VALUE
57 *
58 * REVISIONS
59 */
60 NTSTATUS STDCALL
61 IopCreateFile(PVOID ObjectBody,
62 PVOID Parent,
63 PWSTR RemainingPath,
64 POBJECT_ATTRIBUTES ObjectAttributes)
65 {
66 PDEVICE_OBJECT DeviceObject;
67 PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody;
68 POBJECT_TYPE ParentObjectType;
69 NTSTATUS Status;
70
71 DPRINT("IopCreateFile(ObjectBody %x, Parent %x, RemainingPath %S)\n",
72 ObjectBody,
73 Parent,
74 RemainingPath);
75
76 if (NULL == Parent)
77 {
78 /* This is probably an attempt to create a meta fileobject (eg. for FAT)
79 for the cache manager, so return STATUS_SUCCESS */
80 DPRINT("Parent object was NULL\n");
81 return(STATUS_SUCCESS);
82 }
83
84 ParentObjectType = BODY_TO_HEADER(Parent)->ObjectType;
85
86 if (ParentObjectType != IoDeviceObjectType &&
87 ParentObjectType != IoFileObjectType)
88 {
89 CPRINT("Parent is a %S which is neither a file type nor a device type\n",
90 BODY_TO_HEADER(Parent)->ObjectType->TypeName.Buffer);
91 return(STATUS_UNSUCCESSFUL);
92 }
93
94 Status = ObReferenceObjectByPointer(Parent,
95 STANDARD_RIGHTS_REQUIRED,
96 ParentObjectType,
97 UserMode);
98 if (!NT_SUCCESS(Status))
99 {
100 CPRINT("Failed to reference parent object %x\n", Parent);
101 return(Status);
102 }
103
104 if (ParentObjectType == IoDeviceObjectType)
105 {
106 /* Parent is a devce object */
107 DeviceObject = IoGetAttachedDevice((PDEVICE_OBJECT)Parent);
108 DPRINT("DeviceObject %x\n", DeviceObject);
109
110 if (RemainingPath == NULL)
111 {
112 FileObject->Flags = FileObject->Flags | FO_DIRECT_DEVICE_OPEN;
113 FileObject->FileName.Buffer = 0;
114 FileObject->FileName.Length = FileObject->FileName.MaximumLength = 0;
115 }
116 else
117 {
118 if ((DeviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM)
119 && (DeviceObject->DeviceType != FILE_DEVICE_DISK)
120 && (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
121 && (DeviceObject->DeviceType != FILE_DEVICE_TAPE)
122 && (DeviceObject->DeviceType != FILE_DEVICE_NETWORK)
123 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
124 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
125 {
126 CPRINT("Device was wrong type\n");
127 return(STATUS_UNSUCCESSFUL);
128 }
129
130 if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
131 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
132 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
133 {
134 if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
135 {
136 DPRINT("Mount the logical volume\n");
137 Status = IoMountVolume(DeviceObject, FALSE);
138 DPRINT("Status %x\n", Status);
139 if (!NT_SUCCESS(Status))
140 {
141 CPRINT("Failed to mount logical volume (Status %x)\n",
142 Status);
143 return(Status);
144 }
145 }
146 DeviceObject = DeviceObject->Vpb->DeviceObject;
147 DPRINT("FsDeviceObject %lx\n", DeviceObject);
148 }
149 RtlCreateUnicodeString(&(FileObject->FileName),
150 RemainingPath);
151 }
152 }
153 else
154 {
155 /* Parent is a file object */
156 if (RemainingPath == NULL)
157 {
158 CPRINT("Device is unnamed\n");
159 return STATUS_UNSUCCESSFUL;
160 }
161
162 DeviceObject = ((PFILE_OBJECT)Parent)->DeviceObject;
163 DPRINT("DeviceObject %x\n", DeviceObject);
164
165 FileObject->RelatedFileObject = (PFILE_OBJECT)Parent;
166
167 RtlCreateUnicodeString(&(FileObject->FileName),
168 RemainingPath);
169 }
170
171 DPRINT("FileObject->FileName %wZ\n",
172 &FileObject->FileName);
173 FileObject->DeviceObject = DeviceObject;
174 DPRINT("FileObject %x DeviceObject %x\n",
175 FileObject,
176 DeviceObject);
177 FileObject->Vpb = DeviceObject->Vpb;
178 FileObject->Type = InternalFileType;
179
180 return(STATUS_SUCCESS);
181 }
182
183
184 /**********************************************************************
185 * NAME EXPORTED
186 * IoCreateStreamFileObject@8
187 *
188 * DESCRIPTION
189 *
190 * ARGUMENTS
191 * FileObject
192 * ?
193 *
194 * DeviceObject
195 * ?
196 *
197 * RETURN VALUE
198 *
199 * NOTE
200 *
201 * REVISIONS
202 *
203 * @implemented
204 */
205 PFILE_OBJECT STDCALL
206 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
207 PDEVICE_OBJECT DeviceObject)
208 {
209 PFILE_OBJECT CreatedFileObject;
210 NTSTATUS Status;
211
212 DPRINT("IoCreateStreamFileObject(FileObject %x, DeviceObject %x)\n",
213 FileObject, DeviceObject);
214
215 assert_irql(PASSIVE_LEVEL);
216
217 Status = ObCreateObject(KernelMode,
218 IoFileObjectType,
219 NULL,
220 KernelMode,
221 NULL,
222 sizeof(FILE_OBJECT),
223 0,
224 0,
225 (PVOID*)&CreatedFileObject);
226 if (!NT_SUCCESS(Status))
227 {
228 DPRINT("Could not create FileObject\n");
229 return (NULL);
230 }
231
232 if (FileObject != NULL)
233 {
234 DeviceObject = FileObject->DeviceObject;
235 }
236 DeviceObject = IoGetAttachedDevice(DeviceObject);
237
238 DPRINT("DeviceObject %x\n", DeviceObject);
239
240 CreatedFileObject->DeviceObject = DeviceObject->Vpb->DeviceObject;
241 CreatedFileObject->Vpb = DeviceObject->Vpb;
242 CreatedFileObject->Type = InternalFileType;
243 CreatedFileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
244
245 // shouldn't we initialize the lock event, and several other things here too?
246 KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
247
248 return CreatedFileObject;
249 }
250
251
252 /**********************************************************************
253 * NAME EXPORTED
254 * IoCreateFile@56
255 *
256 * DESCRIPTION
257 * Either causes a new file or directory to be created, or it
258 * opens an existing file, device, directory or volume, giving
259 * the caller a handle for the file object. This handle can be
260 * used by subsequent calls to manipulate data within the file
261 * or the file object's state of attributes.
262 *
263 * ARGUMENTS
264 * FileHandle (OUT)
265 * Points to a variable which receives the file handle
266 * on return;
267 *
268 * DesiredAccess
269 * Desired access to the file;
270 *
271 * ObjectAttributes
272 * Structure describing the file;
273 *
274 * IoStatusBlock (OUT)
275 * Receives information about the operation on return;
276 *
277 * AllocationSize [OPTIONAL]
278 * Initial size of the file in bytes;
279 *
280 * FileAttributes
281 * Attributes to create the file with;
282 *
283 * ShareAccess
284 * Type of shared access the caller would like to the
285 * file;
286 *
287 * CreateDisposition
288 * Specifies what to do, depending on whether the
289 * file already exists;
290 *
291 * CreateOptions
292 * Options for creating a new file;
293 *
294 * EaBuffer [OPTIONAL]
295 * Undocumented;
296 *
297 * EaLength
298 * Undocumented;
299 *
300 * CreateFileType
301 * Type of file (normal, named pipe, mailslot) to create;
302 *
303 * ExtraCreateParameters [OPTIONAL]
304 * Additional creation data for named pipe and mailsots;
305 *
306 * Options
307 * Undocumented.
308 *
309 * RETURN VALUE
310 * Status
311 *
312 * NOTE
313 * Prototype taken from Bo Branten's ntifs.h v15.
314 * Description taken from old NtCreateFile's which is
315 * now a wrapper of this call.
316 *
317 * REVISIONS
318 *
319 * @implemented
320 */
321 NTSTATUS STDCALL
322 IoCreateFile(OUT PHANDLE FileHandle,
323 IN ACCESS_MASK DesiredAccess,
324 IN POBJECT_ATTRIBUTES ObjectAttributes,
325 OUT PIO_STATUS_BLOCK IoStatusBlock,
326 IN PLARGE_INTEGER AllocationSize OPTIONAL,
327 IN ULONG FileAttributes,
328 IN ULONG ShareAccess,
329 IN ULONG CreateDisposition,
330 IN ULONG CreateOptions,
331 IN PVOID EaBuffer OPTIONAL,
332 IN ULONG EaLength,
333 IN CREATE_FILE_TYPE CreateFileType,
334 IN PVOID ExtraCreateParameters OPTIONAL,
335 IN ULONG Options)
336 {
337 PFILE_OBJECT FileObject;
338 NTSTATUS Status;
339 PIRP Irp;
340 PIO_STACK_LOCATION StackLoc;
341 IO_SECURITY_CONTEXT SecurityContext;
342 KPROCESSOR_MODE PreviousMode;
343
344 DPRINT("IoCreateFile(FileHandle %x, DesiredAccess %x, "
345 "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
346 FileHandle,DesiredAccess,ObjectAttributes,
347 ObjectAttributes->ObjectName->Buffer);
348
349 assert_irql(PASSIVE_LEVEL);
350
351 if (IoStatusBlock == NULL)
352 return STATUS_ACCESS_VIOLATION;
353
354 *FileHandle = 0;
355
356 PreviousMode = ExGetPreviousMode();
357
358 Status = ObCreateObject(PreviousMode,
359 IoFileObjectType,
360 ObjectAttributes,
361 PreviousMode,
362 NULL,
363 sizeof(FILE_OBJECT),
364 0,
365 0,
366 (PVOID*)&FileObject);
367 if (!NT_SUCCESS(Status))
368 {
369 DPRINT("ObCreateObject() failed! (Status %lx)\n", Status);
370 return(Status);
371 }
372
373 RtlMapGenericMask(&DesiredAccess,
374 BODY_TO_HEADER(FileObject)->ObjectType->Mapping);
375
376 Status = ObInsertObject ((PVOID)FileObject,
377 NULL,
378 DesiredAccess,
379 0,
380 NULL,
381 FileHandle);
382 if (!NT_SUCCESS(Status))
383 {
384 DPRINT("ObInsertObject() failed! (Status %lx)\n", Status);
385 ObDereferenceObject (FileObject);
386 return(Status);
387 }
388
389 if (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
390 {
391 FileObject->Flags |= (FO_ALERTABLE_IO | FO_SYNCHRONOUS_IO);
392 }
393 if (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT)
394 {
395 FileObject->Flags |= FO_SYNCHRONOUS_IO;
396 }
397
398 if( CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING )
399 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
400
401 SecurityContext.SecurityQos = NULL; /* ?? */
402 SecurityContext.AccessState = NULL; /* ?? */
403 SecurityContext.DesiredAccess = DesiredAccess;
404 SecurityContext.FullCreateOptions = 0; /* ?? */
405
406 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, TRUE);
407 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
408
409 DPRINT("FileObject %x\n", FileObject);
410 DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
411 /*
412 * Create a new IRP to hand to
413 * the FS driver: this may fail
414 * due to resource shortage.
415 */
416 Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
417 if (Irp == NULL)
418 {
419 ZwClose(*FileHandle);
420 return (STATUS_UNSUCCESSFUL);
421 }
422
423 //trigger FileObject/Event dereferencing
424 Irp->Tail.Overlay.OriginalFileObject = FileObject;
425 Irp->RequestorMode = PreviousMode;
426 Irp->UserIosb = IoStatusBlock;
427 Irp->AssociatedIrp.SystemBuffer = EaBuffer;
428 Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)ExtraCreateParameters;
429 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
430 Irp->UserEvent = &FileObject->Event;
431 if (AllocationSize)
432 {
433 Irp->Overlay.AllocationSize = *AllocationSize;
434 }
435
436 /*
437 * Get the stack location for the new
438 * IRP and prepare it.
439 */
440 StackLoc = IoGetNextIrpStackLocation(Irp);
441 switch (CreateFileType)
442 {
443 default:
444 case CreateFileTypeNone:
445 StackLoc->MajorFunction = IRP_MJ_CREATE;
446 break;
447
448 case CreateFileTypeNamedPipe:
449 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
450 break;
451
452 case CreateFileTypeMailslot:
453 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
454 break;
455 }
456 StackLoc->MinorFunction = 0;
457 StackLoc->Flags = (UCHAR)Options;
458 StackLoc->Control = 0;
459 StackLoc->DeviceObject = FileObject->DeviceObject;
460 StackLoc->FileObject = FileObject;
461 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
462 StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
463 StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
464 StackLoc->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
465 StackLoc->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
466 StackLoc->Parameters.Create.EaLength = EaLength;
467
468 /*
469 * Now call the driver and
470 * possibly wait if it can
471 * not complete the request
472 * immediately.
473 */
474 Status = IofCallDriver(FileObject->DeviceObject, Irp );
475
476 if (Status == STATUS_PENDING)
477 {
478 KeWaitForSingleObject(&FileObject->Event,
479 Executive,
480 PreviousMode,
481 FALSE,
482 NULL);
483 Status = IoStatusBlock->Status;
484 }
485 if (!NT_SUCCESS(Status))
486 {
487 DPRINT("Failing create request with status %x\n", Status);
488 FileObject->DeviceObject = NULL;
489 FileObject->Vpb = NULL;
490
491 ZwClose(*FileHandle);
492 }
493
494 assert_irql(PASSIVE_LEVEL);
495
496 DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
497
498 return (Status);
499 }
500
501
502 /**********************************************************************
503 * NAME EXPORTED
504 * NtCreateFile@44
505 *
506 * DESCRIPTION
507 * Entry point to call IoCreateFile with
508 * default parameters.
509 *
510 * ARGUMENTS
511 * See IoCreateFile.
512 *
513 * RETURN VALUE
514 * See IoCreateFile.
515 *
516 * REVISIONS
517 * 2000-03-25 (ea)
518 * Code originally in NtCreateFile moved in IoCreateFile.
519 *
520 * @implemented
521 */
522 NTSTATUS STDCALL
523 NtCreateFile(PHANDLE FileHandle,
524 ACCESS_MASK DesiredAccess,
525 POBJECT_ATTRIBUTES ObjectAttributes,
526 PIO_STATUS_BLOCK IoStatusBlock,
527 PLARGE_INTEGER AllocateSize,
528 ULONG FileAttributes,
529 ULONG ShareAccess,
530 ULONG CreateDisposition,
531 ULONG CreateOptions,
532 PVOID EaBuffer,
533 ULONG EaLength)
534 {
535 return IoCreateFile(FileHandle,
536 DesiredAccess,
537 ObjectAttributes,
538 IoStatusBlock,
539 AllocateSize,
540 FileAttributes,
541 ShareAccess,
542 CreateDisposition,
543 CreateOptions,
544 EaBuffer,
545 EaLength,
546 CreateFileTypeNone,
547 NULL,
548 0);
549 }
550
551
552 /**********************************************************************
553 * NAME EXPORTED
554 * NtOpenFile@24
555 *
556 * DESCRIPTION
557 * Opens an existing file (simpler than NtCreateFile).
558 *
559 * ARGUMENTS
560 * FileHandle (OUT)
561 * Variable that receives the file handle on return;
562 *
563 * DesiredAccess
564 * Access desired by the caller to the file;
565 *
566 * ObjectAttributes
567 * Structue describing the file to be opened;
568 *
569 * IoStatusBlock (OUT)
570 * Receives details about the result of the
571 * operation;
572 *
573 * ShareAccess
574 * Type of shared access the caller requires;
575 *
576 * OpenOptions
577 * Options for the file open.
578 *
579 * RETURN VALUE
580 * Status.
581 *
582 * NOTE
583 * Undocumented.
584 *
585 * @implemented
586 */
587 NTSTATUS STDCALL
588 NtOpenFile(PHANDLE FileHandle,
589 ACCESS_MASK DesiredAccess,
590 POBJECT_ATTRIBUTES ObjectAttributes,
591 PIO_STATUS_BLOCK IoStatusBlock,
592 ULONG ShareAccess,
593 ULONG OpenOptions)
594 {
595 return IoCreateFile(FileHandle,
596 DesiredAccess,
597 ObjectAttributes,
598 IoStatusBlock,
599 NULL,
600 0,
601 ShareAccess,
602 FILE_OPEN,
603 OpenOptions,
604 NULL,
605 0,
606 CreateFileTypeNone,
607 NULL,
608 0);
609 }
610
611 /* EOF */