IoCreateFile(): Filled in Irp->Flags; not needed
[reactos.git] / 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 <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/io.h>
17 #include <internal/id.h>
18 #include <internal/pool.h>
19
20 #define NDEBUG
21 #include <internal/debug.h>
22
23 /* GLOBALS *******************************************************************/
24
25 #define TAG_FILE_NAME     TAG('F', 'N', 'A', 'M')
26
27 /* FUNCTIONS *************************************************************/
28
29 #ifndef LIBCAPTIVE
30
31 /**********************************************************************
32  * NAME                                                 EXPORTED
33  *      NtDeleteFile@4
34  *      
35  * DESCRIPTION
36  *      
37  * ARGUMENTS
38  *      ObjectAttributes
39  *              ?
40  *
41  * RETURN VALUE
42  *
43  * REVISIONS
44  * 
45  */
46 NTSTATUS STDCALL
47 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
48 {
49   UNIMPLEMENTED;
50 }
51
52 #endif /* LIBCAPTIVE */
53
54 /**********************************************************************
55  * NAME                                                 INTERNAL
56  *      IopCreateFile
57  *      
58  * DESCRIPTION
59  *      
60  * ARGUMENTS
61  *              
62  * RETURN VALUE
63  *
64  * REVISIONS
65  * 
66  */
67 NTSTATUS STDCALL
68 IopCreateFile(PVOID                     ObjectBody,
69               PVOID                     Parent,
70               PWSTR                     RemainingPath,
71               POBJECT_ATTRIBUTES        ObjectAttributes)
72 {
73   PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT) Parent;
74   PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody;
75   NTSTATUS Status;
76
77   DPRINT("IopCreateFile(ObjectBody %x, Parent %x, RemainingPath %S)\n",
78          ObjectBody,
79          Parent,
80          RemainingPath);
81
82   if (NULL == DeviceObject)
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("DeviceObject was NULL\n");
87       return(STATUS_SUCCESS);
88     }
89
90   if (IoDeviceObjectType != BODY_TO_HEADER(Parent)->ObjectType)
91     {
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);
95     }
96
97   Status = ObReferenceObjectByPointer(DeviceObject,
98                                       STANDARD_RIGHTS_REQUIRED,
99                                       IoDeviceObjectType,
100                                       UserMode);
101   if (!NT_SUCCESS(Status))
102     {
103       CPRINT("Failed to reference device object %x\n", DeviceObject);
104       return(Status);
105     }
106
107   FileObject->Flags = 0;
108
109   DeviceObject = IoGetAttachedDevice(DeviceObject);
110   DPRINT("DeviceObject %x\n", DeviceObject);
111
112   if (NULL == RemainingPath)
113     {
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;
118     }
119   else
120     {
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))
128         {
129           CPRINT("Device was wrong type\n");
130           KeBugCheck(0);
131           return(STATUS_UNSUCCESSFUL);
132         }
133
134       if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
135           && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
136           && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
137         {
138           if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
139             {
140               DPRINT("Mount the logical volume\n");
141               Status = IoMountVolume(DeviceObject, FALSE);
142               DPRINT("Status %x\n", Status);
143               if (!NT_SUCCESS(Status))
144                 {
145                   CPRINT("Failed to mount logical volume (Status %x)\n",
146                          Status);
147                   return(Status);
148                 }
149               if (!DeviceObject->Vpb)
150                 KeBugCheck(0);
151               if (DeviceObject->Vpb->DeviceObject->Vpb)
152                 KeBugCheck(0);
153               DeviceObject->Vpb->DeviceObject->Vpb=DeviceObject->Vpb;
154               DeviceObject->Vpb->Flags |= VPB_MOUNTED;
155             }
156
157           DeviceObject = DeviceObject->Vpb->DeviceObject;
158           DPRINT("FsDeviceObject %lx\n", DeviceObject);
159         }
160       RtlCreateUnicodeString(&(FileObject->FileName),
161                              RemainingPath);
162       FileObject->Vpb = NULL;
163     }
164
165   DPRINT("FileObject->FileName %wZ\n",
166          &FileObject->FileName);
167   FileObject->DeviceObject = DeviceObject;
168   DPRINT("FileObject %x DeviceObject %x\n",
169          FileObject,
170          DeviceObject);
171   FileObject->Type = InternalFileType;
172   FileObject->RelatedFileObject = NULL;
173
174   return(STATUS_SUCCESS);
175 }
176
177
178 /**********************************************************************
179  * NAME                                                 EXPORTED
180  *      IoCreateStreamFileObject@8
181  *      
182  * DESCRIPTION
183  *      
184  * ARGUMENTS
185  *      FileObject
186  *              ?
187  *              
188  *      DeviceObject
189  *              ?
190  *              
191  * RETURN VALUE
192  *
193  * NOTE
194  *      
195  * REVISIONS
196  * 
197  */
198 PFILE_OBJECT STDCALL
199 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
200                          PDEVICE_OBJECT DeviceObject)
201 {
202   PFILE_OBJECT  CreatedFileObject;
203   NTSTATUS Status;
204
205   DPRINT("IoCreateStreamFileObject(FileObject %x, DeviceObject %x)\n",
206          FileObject, DeviceObject);
207
208   assert_irql(PASSIVE_LEVEL);
209
210   /* We don't need any 'Handle' therefore pass 1st parameter as NULL and it
211    * will not be created by ObCreateObject() at all.
212    */
213   Status = ObCreateObject(NULL,
214                           STANDARD_RIGHTS_REQUIRED,
215                           NULL,
216                           IoFileObjectType,
217                           (PVOID*)&CreatedFileObject);
218   if (!NT_SUCCESS(Status))
219     {
220       DPRINT("Could not create FileObject\n");
221       return (NULL);
222     }
223
224   if (FileObject != NULL)
225     {
226       DeviceObject = FileObject->DeviceObject;
227     }
228   DeviceObject = IoGetAttachedDevice(DeviceObject);
229
230   DPRINT("DeviceObject %x\n", DeviceObject);
231
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.
237    */
238   CreatedFileObject->Flags |= FO_STREAM_FILE;
239 #ifdef LIBCAPTIVE
240   /* We are fully single-threaded/single-processed;
241    * prevent at least IopDeleteFile()->...->IoIsOperationSynchronous() to return FALSE
242    */
243   CreatedFileObject->Flags |= FO_SYNCHRONOUS_IO;
244 #endif /* LIBCAPTIVE */
245   CreatedFileObject->FileName.Length=0;
246   CreatedFileObject->FileName.MaximumLength=0;
247   CreatedFileObject->FileName.Buffer=NULL;
248
249   // shouldn't we initialize the lock event, and several other things here too?
250   KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
251
252   return(CreatedFileObject);
253 }
254
255
256 /**********************************************************************
257  * NAME                                                 EXPORTED
258  *      IoCreateFile@56
259  *      
260  * DESCRIPTION
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.
266  *      
267  * ARGUMENTS
268  *      FileHandle (OUT)
269  *              Points to a variable which receives the file handle
270  *              on return;
271  *              
272  *      DesiredAccess
273  *              Desired access to the file;
274  *              
275  *      ObjectAttributes
276  *              Structure describing the file;
277  *              
278  *      IoStatusBlock (OUT)
279  *              Receives information about the operation on return;
280  *              
281  *      AllocationSize [OPTIONAL]
282  *              Initial size of the file in bytes;
283  *              
284  *      FileAttributes
285  *              Attributes to create the file with;
286  *              
287  *      ShareAccess
288  *              Type of shared access the caller would like to the
289  *              file;
290  *              
291  *      CreateDisposition
292  *              Specifies what to do, depending on whether the
293  *              file already exists;
294  *              
295  *      CreateOptions
296  *              Options for creating a new file;
297  *              
298  *      EaBuffer [OPTIONAL]
299  *              Undocumented;
300  *              
301  *      EaLength
302  *              Undocumented;
303  *              
304  *      CreateFileType
305  *              Type of file (normal, named pipe, mailslot) to create;
306  *              
307  *      ExtraCreateParameters [OPTIONAL]
308  *              Additional creation data for named pipe and mailsots;
309  *              
310  *      Options
311  *              Undocumented.
312  *              
313  * RETURN VALUE
314  *      Status
315  *
316  * NOTE
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.
320  *      
321  * REVISIONS
322  * 
323  */
324 NTSTATUS STDCALL
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,
335              IN ULONG                   EaLength,
336              IN CREATE_FILE_TYPE        CreateFileType,
337              IN PVOID                   ExtraCreateParameters   OPTIONAL,
338              IN ULONG                   Options)
339 {
340    PFILE_OBJECT         FileObject;
341    NTSTATUS             Status;
342    PIRP                 Irp;
343    PIO_STACK_LOCATION   StackLoc;
344    IO_STATUS_BLOCK      IoSB;
345    IO_SECURITY_CONTEXT  SecurityContext;
346    ACCESS_STATE         AccessState;
347    
348    DPRINT("IoCreateFile(FileHandle %x, DesiredAccess %x, "
349           "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
350           FileHandle,DesiredAccess,ObjectAttributes,
351           ObjectAttributes->ObjectName->Buffer);
352    
353    assert_irql(PASSIVE_LEVEL);
354    
355    *FileHandle = 0;
356
357    Status = ObCreateObject(FileHandle,
358                            DesiredAccess,
359                            ObjectAttributes,
360                            IoFileObjectType,
361                            (PVOID*)&FileObject);
362    if (!NT_SUCCESS(Status))
363      {
364         DPRINT("ObCreateObject() failed! (Status %lx)\n", Status);
365         return(Status);
366      }
367    if (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
368      {
369         FileObject->Flags |= (FO_ALERTABLE_IO | FO_SYNCHRONOUS_IO);
370      }
371    if (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT)
372      {
373         FileObject->Flags |= FO_SYNCHRONOUS_IO;
374      }
375
376    if( CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING )
377      FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
378
379    FileObject->FsContext=NULL;
380    FileObject->FsContext2=NULL;
381
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
386     * W32 undocumented.
387     */
388    AccessState.OriginalDesiredAccess=DesiredAccess;     /* FIXME: Meaning? */
389
390    SecurityContext.SecurityQos = NULL; /* ?? */
391    SecurityContext.AccessState = &AccessState;
392    SecurityContext.DesiredAccess = DesiredAccess;
393    SecurityContext.FullCreateOptions = 0; /* ?? */
394    
395    KeInitializeEvent(&FileObject->Lock, NotificationEvent, TRUE);
396    KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
397    
398    DPRINT("FileObject %x\n", FileObject);
399    DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
400    /*
401     * Create a new IRP to hand to
402     * the FS driver: this may fail
403     * due to resource shortage.
404     */
405    Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
406    if (Irp == NULL)
407      {
408         ZwClose(*FileHandle);
409         return (STATUS_UNSUCCESSFUL);
410      }
411      
412 #ifdef LIBCAPTIVE
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
415     */
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;
423    if (AllocationSize)
424    {
425       Irp->Overlay.AllocationSize = *AllocationSize;
426    }
427    /* Is it needed? What it means? It was seen in NT-5.1sp1 */
428    Irp->Tail.Overlay.OriginalFileObject = FileObject;
429    
430    /*
431     * Get the stack location for the new
432     * IRP and prepare it.
433     */
434    StackLoc = IoGetNextIrpStackLocation(Irp);
435    switch (CreateFileType)
436      {
437         default:
438         case CreateFileTypeNone:
439           StackLoc->MajorFunction = IRP_MJ_CREATE;
440           break;
441         
442         case CreateFileTypeNamedPipe:
443           StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
444           break;
445
446         case CreateFileTypeMailslot:
447           StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
448           break;
449      }
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;
461    
462 #ifdef LIBCAPTIVE
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.
468     */
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)
484      {
485        FileObject->FileName.Length=0;
486        FileObject->FileName.Buffer=NULL;
487      }
488 #endif /* LIBCAPTIVE */
489
490    /*
491     * Now call the driver and 
492     * possibly wait if it can
493     * not complete the request
494     * immediately.
495     */
496    Status = IofCallDriver(FileObject->DeviceObject, Irp );
497    
498    if (Status == STATUS_PENDING)
499      {
500         KeWaitForSingleObject(&FileObject->Event,
501                               Executive,
502                               KernelMode,
503                               FALSE,
504                               NULL);
505         Status = IoSB.Status;
506      }
507    if (!NT_SUCCESS(Status))
508      {
509         DPRINT("Failing create request with status %x\n", Status);
510         FileObject->DeviceObject = NULL;
511         FileObject->Vpb = NULL;
512
513         ZwClose(*FileHandle);
514      }
515    if (IoStatusBlock)
516      {
517        *IoStatusBlock = IoSB;
518      }
519    assert_irql(PASSIVE_LEVEL);
520
521    DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
522
523    return (Status);
524 }
525
526 #ifndef LIBCAPTIVE
527
528 /**********************************************************************
529  * NAME                                                 EXPORTED
530  *      NtCreateFile@44
531  * 
532  * DESCRIPTION
533  *      Entry point to call IoCreateFile with
534  *      default parameters.
535  *
536  * ARGUMENTS
537  *      See IoCreateFile.
538  * 
539  * RETURN VALUE
540  *      See IoCreateFile.
541  *
542  * REVISIONS
543  *      2000-03-25 (ea)
544  *              Code originally in NtCreateFile moved in IoCreateFile.
545  */
546 NTSTATUS STDCALL
547 NtCreateFile(PHANDLE FileHandle,
548              ACCESS_MASK DesiredAccess,
549              POBJECT_ATTRIBUTES ObjectAttributes,
550              PIO_STATUS_BLOCK IoStatusBlock,
551              PLARGE_INTEGER AllocateSize,
552              ULONG FileAttributes,
553              ULONG ShareAccess,
554              ULONG CreateDisposition,
555              ULONG CreateOptions,
556              PVOID EaBuffer,
557              ULONG EaLength)
558 {
559    return IoCreateFile(FileHandle,
560                        DesiredAccess,
561                        ObjectAttributes,
562                        IoStatusBlock,
563                        AllocateSize,
564                        FileAttributes,
565                        ShareAccess,
566                        CreateDisposition,
567                        CreateOptions,
568                        EaBuffer,
569                        EaLength,
570                        CreateFileTypeNone,
571                        NULL,
572                        0);
573 }
574
575
576 /**********************************************************************
577  * NAME                                                 EXPORTED
578  *      NtOpenFile@24
579  *      
580  * DESCRIPTION
581  *      Opens an existing file (simpler than NtCreateFile).
582  *
583  * ARGUMENTS
584  *      FileHandle (OUT)
585  *              Variable that receives the file handle on return;
586  *              
587  *      DesiredAccess
588  *              Access desired by the caller to the file;
589  *              
590  *      ObjectAttributes
591  *              Structue describing the file to be opened;
592  *              
593  *      IoStatusBlock (OUT)
594  *              Receives details about the result of the
595  *              operation;
596  *              
597  *      ShareAccess
598  *              Type of shared access the caller requires;
599  *              
600  *      OpenOptions
601  *              Options for the file open.
602  *
603  * RETURN VALUE
604  *      Status.
605  *      
606  * NOTE
607  *      Undocumented.
608  */
609 NTSTATUS STDCALL
610 NtOpenFile(PHANDLE FileHandle,
611            ACCESS_MASK DesiredAccess,
612            POBJECT_ATTRIBUTES ObjectAttributes,
613            PIO_STATUS_BLOCK IoStatusBlock,
614            ULONG ShareAccess,
615            ULONG OpenOptions)
616 {
617    return IoCreateFile(FileHandle,
618                        DesiredAccess,
619                        ObjectAttributes,
620                        IoStatusBlock,
621                        NULL,
622                        0,
623                        ShareAccess,
624                        FILE_OPEN,
625                        OpenOptions,
626                        NULL,
627                        0,
628                        CreateFileTypeNone,
629                        NULL,
630                        0);
631 }
632
633 #endif /* LIBCAPTIVE */
634
635 /* EOF */