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