migrate substitution keywords to SVN
[reactos.git] / reactos / ntoskrnl / io / create.c
1 /* $Id$
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 = NULL;
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 StackLoc->MinorFunction = 0;
442 StackLoc->Flags = (UCHAR)Options;
443 StackLoc->Control = 0;
444 StackLoc->DeviceObject = FileObject->DeviceObject;
445 StackLoc->FileObject = FileObject;
446
447 switch (CreateFileType)
448 {
449 default:
450 case CreateFileTypeNone:
451 StackLoc->MajorFunction = IRP_MJ_CREATE;
452 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
453 StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
454 StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
455 StackLoc->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
456 StackLoc->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
457 StackLoc->Parameters.Create.EaLength = EaLength;
458 break;
459
460 case CreateFileTypeNamedPipe:
461 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
462 StackLoc->Parameters.CreatePipe.SecurityContext = &SecurityContext;
463 StackLoc->Parameters.CreatePipe.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
464 StackLoc->Parameters.CreatePipe.Options |= (CreateDisposition << 24);
465 StackLoc->Parameters.CreatePipe.ShareAccess = (USHORT)ShareAccess;
466 StackLoc->Parameters.CreatePipe.Parameters = ExtraCreateParameters;
467 break;
468
469 case CreateFileTypeMailslot:
470 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
471 StackLoc->Parameters.CreateMailslot.SecurityContext = &SecurityContext;
472 StackLoc->Parameters.CreateMailslot.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
473 StackLoc->Parameters.CreateMailslot.Options |= (CreateDisposition << 24);
474 StackLoc->Parameters.CreateMailslot.ShareAccess = (USHORT)ShareAccess;
475 StackLoc->Parameters.CreateMailslot.Parameters = ExtraCreateParameters;
476 break;
477 }
478
479 /*
480 * Now call the driver and
481 * possibly wait if it can
482 * not complete the request
483 * immediately.
484 */
485 Status = IofCallDriver(FileObject->DeviceObject, Irp );
486
487 if (Status == STATUS_PENDING)
488 {
489 KeWaitForSingleObject(&FileObject->Event,
490 Executive,
491 PreviousMode,
492 FALSE,
493 NULL);
494 Status = IoStatusBlock->Status;
495 }
496 if (!NT_SUCCESS(Status))
497 {
498 DPRINT("Failing create request with status %x\n", Status);
499 FileObject->DeviceObject = NULL;
500 FileObject->Vpb = NULL;
501
502 ZwClose(*FileHandle);
503 }
504
505 ASSERT_IRQL(PASSIVE_LEVEL);
506
507 DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
508
509 return Status;
510 }
511
512
513 /**********************************************************************
514 * NAME EXPORTED
515 * NtCreateFile@44
516 *
517 * DESCRIPTION
518 * Entry point to call IoCreateFile with
519 * default parameters.
520 *
521 * ARGUMENTS
522 * See IoCreateFile.
523 *
524 * RETURN VALUE
525 * See IoCreateFile.
526 *
527 * REVISIONS
528 * 2000-03-25 (ea)
529 * Code originally in NtCreateFile moved in IoCreateFile.
530 *
531 * @implemented
532 */
533 NTSTATUS STDCALL
534 NtCreateFile(PHANDLE FileHandle,
535 ACCESS_MASK DesiredAccess,
536 POBJECT_ATTRIBUTES ObjectAttributes,
537 PIO_STATUS_BLOCK IoStatusBlock,
538 PLARGE_INTEGER AllocateSize,
539 ULONG FileAttributes,
540 ULONG ShareAccess,
541 ULONG CreateDisposition,
542 ULONG CreateOptions,
543 PVOID EaBuffer,
544 ULONG EaLength)
545 {
546 return IoCreateFile(FileHandle,
547 DesiredAccess,
548 ObjectAttributes,
549 IoStatusBlock,
550 AllocateSize,
551 FileAttributes,
552 ShareAccess,
553 CreateDisposition,
554 CreateOptions,
555 EaBuffer,
556 EaLength,
557 CreateFileTypeNone,
558 NULL,
559 0);
560 }
561
562
563 /**********************************************************************
564 * NAME EXPORTED
565 * NtOpenFile@24
566 *
567 * DESCRIPTION
568 * Opens an existing file (simpler than NtCreateFile).
569 *
570 * ARGUMENTS
571 * FileHandle (OUT)
572 * Variable that receives the file handle on return;
573 *
574 * DesiredAccess
575 * Access desired by the caller to the file;
576 *
577 * ObjectAttributes
578 * Structue describing the file to be opened;
579 *
580 * IoStatusBlock (OUT)
581 * Receives details about the result of the
582 * operation;
583 *
584 * ShareAccess
585 * Type of shared access the caller requires;
586 *
587 * OpenOptions
588 * Options for the file open.
589 *
590 * RETURN VALUE
591 * Status.
592 *
593 * NOTE
594 * Undocumented.
595 *
596 * @implemented
597 */
598 NTSTATUS STDCALL
599 NtOpenFile(PHANDLE FileHandle,
600 ACCESS_MASK DesiredAccess,
601 POBJECT_ATTRIBUTES ObjectAttributes,
602 PIO_STATUS_BLOCK IoStatusBlock,
603 ULONG ShareAccess,
604 ULONG OpenOptions)
605 {
606 return IoCreateFile(FileHandle,
607 DesiredAccess,
608 ObjectAttributes,
609 IoStatusBlock,
610 NULL,
611 0,
612 ShareAccess,
613 FILE_OPEN,
614 OpenOptions,
615 NULL,
616 0,
617 CreateFileTypeNone,
618 NULL,
619 0);
620 }
621
622 /* EOF */