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)
12 /* INCLUDES ***************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/io.h>
17 #include <internal/id.h>
18 #include <internal/pool.h>
21 #include <internal/debug.h>
23 /* GLOBALS *******************************************************************/
25 #define TAG_FILE_NAME TAG('F', 'N', 'A', 'M')
27 /* FUNCTIONS *************************************************************/
31 /**********************************************************************
47 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
52 #endif /* LIBCAPTIVE */
54 /**********************************************************************
68 IopCreateFile(PVOID ObjectBody,
71 POBJECT_ATTRIBUTES ObjectAttributes)
73 PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) Parent;
74 PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody;
77 DPRINT("IopCreateFile(ObjectBody %x, Parent %x, RemainingPath %S)\n",
82 if (NULL == DeviceObject)
84 /* This is probably an attempt to create a meta fileobject (eg. for FAT)
85 for the cache manager, so return STATUS_SUCCESS */
86 DPRINT("DeviceObject was NULL\n");
87 return(STATUS_SUCCESS);
90 if (IoDeviceObjectType != BODY_TO_HEADER(Parent)->ObjectType)
92 CPRINT("Parent is a %S which is not a device type\n",
93 BODY_TO_HEADER(Parent)->ObjectType->TypeName.Buffer);
94 return(STATUS_UNSUCCESSFUL);
97 Status = ObReferenceObjectByPointer(DeviceObject,
98 STANDARD_RIGHTS_REQUIRED,
101 if (!NT_SUCCESS(Status))
103 CPRINT("Failed to reference device object %x\n", DeviceObject);
107 FileObject->Flags = 0;
109 DeviceObject = IoGetAttachedDevice(DeviceObject);
110 DPRINT("DeviceObject %x\n", DeviceObject);
112 if (NULL == RemainingPath)
114 FileObject->Flags = FileObject->Flags | FO_DIRECT_DEVICE_OPEN;
115 FileObject->FileName.Buffer = 0;
116 FileObject->FileName.Length = FileObject->FileName.MaximumLength = 0;
117 FileObject->Vpb = DeviceObject->Vpb;
121 if ((DeviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM)
122 && (DeviceObject->DeviceType != FILE_DEVICE_DISK)
123 && (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
124 && (DeviceObject->DeviceType != FILE_DEVICE_TAPE)
125 && (DeviceObject->DeviceType != FILE_DEVICE_NETWORK)
126 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
127 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
129 CPRINT("Device was wrong type\n");
131 return(STATUS_UNSUCCESSFUL);
134 if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
135 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
136 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
138 if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
140 DPRINT("Mount the logical volume\n");
141 Status = IoMountVolume(DeviceObject, FALSE);
142 DPRINT("Status %x\n", Status);
143 if (!NT_SUCCESS(Status))
145 CPRINT("Failed to mount logical volume (Status %x)\n",
149 if (!DeviceObject->Vpb)
151 if (DeviceObject->Vpb->DeviceObject->Vpb)
153 DeviceObject->Vpb->DeviceObject->Vpb=DeviceObject->Vpb;
154 DeviceObject->Vpb->Flags |= VPB_MOUNTED;
157 DeviceObject = DeviceObject->Vpb->DeviceObject;
158 DPRINT("FsDeviceObject %lx\n", DeviceObject);
160 RtlCreateUnicodeString(&(FileObject->FileName),
162 FileObject->Vpb = NULL;
165 DPRINT("FileObject->FileName %wZ\n",
166 &FileObject->FileName);
167 FileObject->DeviceObject = DeviceObject;
168 DPRINT("FileObject %x DeviceObject %x\n",
171 FileObject->Type = InternalFileType;
172 FileObject->RelatedFileObject = NULL;
174 return(STATUS_SUCCESS);
178 /**********************************************************************
180 * IoCreateStreamFileObject@8
199 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
200 PDEVICE_OBJECT DeviceObject)
202 PFILE_OBJECT CreatedFileObject;
205 DPRINT("IoCreateStreamFileObject(FileObject %x, DeviceObject %x)\n",
206 FileObject, DeviceObject);
208 assert_irql(PASSIVE_LEVEL);
210 /* We don't need any 'Handle' therefore pass 1st parameter as NULL and it
211 * will not be created by ObCreateObject() at all.
213 Status = ObCreateObject(NULL,
214 STANDARD_RIGHTS_REQUIRED,
217 (PVOID*)&CreatedFileObject);
218 if (!NT_SUCCESS(Status))
220 DPRINT("Could not create FileObject\n");
224 if (FileObject != NULL)
226 DeviceObject = FileObject->DeviceObject;
228 DeviceObject = IoGetAttachedDevice(DeviceObject);
230 DPRINT("DeviceObject %x\n", DeviceObject);
232 CreatedFileObject->DeviceObject = DeviceObject->Vpb->DeviceObject;
233 CreatedFileObject->Vpb = DeviceObject->Vpb;
234 CreatedFileObject->Type = InternalFileType;
235 /* Why was FO_DIRECT_DEVICE_OPEN used here before?
236 * FO_STREAM_FILE is according to W32 documentation.
238 CreatedFileObject->Flags |= FO_STREAM_FILE;
240 /* We are fully single-threaded/single-processed;
241 * prevent at least IopDeleteFile()->...->IoIsOperationSynchronous() to return FALSE
243 CreatedFileObject->Flags |= FO_SYNCHRONOUS_IO;
244 #endif /* LIBCAPTIVE */
245 CreatedFileObject->FileName.Length=0;
246 CreatedFileObject->FileName.MaximumLength=0;
247 CreatedFileObject->FileName.Buffer=NULL;
249 // shouldn't we initialize the lock event, and several other things here too?
250 KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
252 return(CreatedFileObject);
256 /**********************************************************************
261 * Either causes a new file or directory to be created, or it
262 * opens an existing file, device, directory or volume, giving
263 * the caller a handle for the file object. This handle can be
264 * used by subsequent calls to manipulate data within the file
265 * or the file object's state of attributes.
269 * Points to a variable which receives the file handle
273 * Desired access to the file;
276 * Structure describing the file;
278 * IoStatusBlock (OUT)
279 * Receives information about the operation on return;
281 * AllocationSize [OPTIONAL]
282 * Initial size of the file in bytes;
285 * Attributes to create the file with;
288 * Type of shared access the caller would like to the
292 * Specifies what to do, depending on whether the
293 * file already exists;
296 * Options for creating a new file;
298 * EaBuffer [OPTIONAL]
305 * Type of file (normal, named pipe, mailslot) to create;
307 * ExtraCreateParameters [OPTIONAL]
308 * Additional creation data for named pipe and mailsots;
317 * Prototype taken from Bo Branten's ntifs.h v15.
318 * Description taken from old NtCreateFile's which is
319 * now a wrapper of this call.
325 IoCreateFile(OUT PHANDLE FileHandle,
326 IN ACCESS_MASK DesiredAccess,
327 IN POBJECT_ATTRIBUTES ObjectAttributes,
328 OUT PIO_STATUS_BLOCK IoStatusBlock,
329 IN PLARGE_INTEGER AllocationSize OPTIONAL,
330 IN ULONG FileAttributes,
331 IN ULONG ShareAccess,
332 IN ULONG CreateDisposition,
333 IN ULONG CreateOptions,
334 IN PVOID EaBuffer OPTIONAL,
336 IN CREATE_FILE_TYPE CreateFileType,
337 IN PVOID ExtraCreateParameters OPTIONAL,
340 PFILE_OBJECT FileObject;
343 PIO_STACK_LOCATION StackLoc;
344 IO_STATUS_BLOCK IoSB;
345 IO_SECURITY_CONTEXT SecurityContext;
346 ACCESS_STATE AccessState;
348 DPRINT("IoCreateFile(FileHandle %x, DesiredAccess %x, "
349 "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
350 FileHandle,DesiredAccess,ObjectAttributes,
351 ObjectAttributes->ObjectName->Buffer);
353 assert_irql(PASSIVE_LEVEL);
357 Status = ObCreateObject(FileHandle,
361 (PVOID*)&FileObject);
362 if (!NT_SUCCESS(Status))
364 DPRINT("ObCreateObject() failed! (Status %lx)\n", Status);
367 if (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
369 FileObject->Flags |= (FO_ALERTABLE_IO | FO_SYNCHRONOUS_IO);
371 if (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT)
373 FileObject->Flags |= FO_SYNCHRONOUS_IO;
376 if( CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING )
377 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
379 FileObject->FsContext=NULL;
380 FileObject->FsContext2=NULL;
382 RtlZeroMemory(&AccessState, sizeof(AccessState));
383 AccessState.RemainingDesiredAccess=0; /* FIXME: Meaning? */
384 AccessState.PreviouslyGrantedAccess=DesiredAccess; /* FIXME: Meaning? */
385 /* 'OriginalDesiredAccess' is required during file create by ntfs.sys of NT-5.1sp1
388 AccessState.OriginalDesiredAccess=DesiredAccess; /* FIXME: Meaning? */
390 SecurityContext.SecurityQos = NULL; /* ?? */
391 SecurityContext.AccessState = &AccessState;
392 SecurityContext.DesiredAccess = DesiredAccess;
393 SecurityContext.FullCreateOptions = 0; /* ?? */
395 KeInitializeEvent(&FileObject->Lock, NotificationEvent, TRUE);
396 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
398 DPRINT("FileObject %x\n", FileObject);
399 DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
401 * Create a new IRP to hand to
402 * the FS driver: this may fail
403 * due to resource shortage.
405 Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
408 ZwClose(*FileHandle);
409 return (STATUS_UNSUCCESSFUL);
413 /* Is it needed? What it means? It was seen in NT-5.1sp1 as
414 * IRP_DEFER_IO_COMPLETION | IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API
416 Irp->Flags = IRP_SYNCHRONOUS_API;
417 #endif /* LIBCAPTIVE */
418 Irp->UserIosb = &IoSB; //return iostatus
419 Irp->AssociatedIrp.SystemBuffer = EaBuffer;
420 Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)ExtraCreateParameters;
421 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
422 Irp->UserEvent = &FileObject->Event;
425 Irp->Overlay.AllocationSize = *AllocationSize;
427 /* Is it needed? What it means? It was seen in NT-5.1sp1 */
428 Irp->Tail.Overlay.OriginalFileObject = FileObject;
431 * Get the stack location for the new
432 * IRP and prepare it.
434 StackLoc = IoGetNextIrpStackLocation(Irp);
435 switch (CreateFileType)
438 case CreateFileTypeNone:
439 StackLoc->MajorFunction = IRP_MJ_CREATE;
442 case CreateFileTypeNamedPipe:
443 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
446 case CreateFileTypeMailslot:
447 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
450 StackLoc->MinorFunction = 0;
451 StackLoc->Flags = Options;
452 StackLoc->Control = 0;
453 StackLoc->DeviceObject = FileObject->DeviceObject;
454 StackLoc->FileObject = FileObject;
455 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
456 StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
457 StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
458 StackLoc->Parameters.Create.FileAttributes = FileAttributes;
459 StackLoc->Parameters.Create.ShareAccess = ShareAccess;
460 StackLoc->Parameters.Create.EaLength = EaLength;
463 /* Needed from libcaptive/client/init.c/dismount_volume()
464 * as we cannot pass just "\Devicename" as it would open the device
465 * itself instead of the filesystem; If passed "\Devicename\", the
466 * trailing '\' will remain in RemainingPath and such open will not
467 * be the VolumeOpen type we need for unmount.
469 if (FileObject->FileName.Length==13*2
470 && FileObject->FileName.Buffer[ 0]==L'\\'
471 && FileObject->FileName.Buffer[ 1]==L'!'
472 && FileObject->FileName.Buffer[ 2]==L'C'
473 && FileObject->FileName.Buffer[ 3]==L'a'
474 && FileObject->FileName.Buffer[ 4]==L'p'
475 && FileObject->FileName.Buffer[ 5]==L't'
476 && FileObject->FileName.Buffer[ 6]==L'i'
477 && FileObject->FileName.Buffer[ 7]==L'v'
478 && FileObject->FileName.Buffer[ 8]==L'e'
479 && FileObject->FileName.Buffer[ 9]==L'!'
480 && FileObject->FileName.Buffer[10]==L'd'
481 && FileObject->FileName.Buffer[11]==L'e'
482 && FileObject->FileName.Buffer[12]==L'l'
483 && FileObject->FileName.Buffer[13]==0)
485 FileObject->FileName.Length=0;
486 FileObject->FileName.Buffer=NULL;
488 #endif /* LIBCAPTIVE */
491 * Now call the driver and
492 * possibly wait if it can
493 * not complete the request
496 Status = IofCallDriver(FileObject->DeviceObject, Irp );
498 if (Status == STATUS_PENDING)
500 KeWaitForSingleObject(&FileObject->Event,
505 Status = IoSB.Status;
507 if (!NT_SUCCESS(Status))
509 DPRINT("Failing create request with status %x\n", Status);
510 FileObject->DeviceObject = NULL;
511 FileObject->Vpb = NULL;
513 ZwClose(*FileHandle);
517 *IoStatusBlock = IoSB;
519 assert_irql(PASSIVE_LEVEL);
521 DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
528 /**********************************************************************
533 * Entry point to call IoCreateFile with
534 * default parameters.
544 * Code originally in NtCreateFile moved in IoCreateFile.
547 NtCreateFile(PHANDLE FileHandle,
548 ACCESS_MASK DesiredAccess,
549 POBJECT_ATTRIBUTES ObjectAttributes,
550 PIO_STATUS_BLOCK IoStatusBlock,
551 PLARGE_INTEGER AllocateSize,
552 ULONG FileAttributes,
554 ULONG CreateDisposition,
559 return IoCreateFile(FileHandle,
576 /**********************************************************************
581 * Opens an existing file (simpler than NtCreateFile).
585 * Variable that receives the file handle on return;
588 * Access desired by the caller to the file;
591 * Structue describing the file to be opened;
593 * IoStatusBlock (OUT)
594 * Receives details about the result of the
598 * Type of shared access the caller requires;
601 * Options for the file open.
610 NtOpenFile(PHANDLE FileHandle,
611 ACCESS_MASK DesiredAccess,
612 POBJECT_ATTRIBUTES ObjectAttributes,
613 PIO_STATUS_BLOCK IoStatusBlock,
617 return IoCreateFile(FileHandle,
633 #endif /* LIBCAPTIVE */