IopCreateFile(): Fix semantics of volume mounting (Vpb vs. Device etc.)
[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    Irp->UserIosb = &IoSB;   //return iostatus
413    Irp->AssociatedIrp.SystemBuffer = EaBuffer;
414    Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)ExtraCreateParameters;
415    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
416    Irp->UserEvent = &FileObject->Event;
417    if (AllocationSize)
418    {
419       Irp->Overlay.AllocationSize = *AllocationSize;
420    }
421    
422    /*
423     * Get the stack location for the new
424     * IRP and prepare it.
425     */
426    StackLoc = IoGetNextIrpStackLocation(Irp);
427    switch (CreateFileType)
428      {
429         default:
430         case CreateFileTypeNone:
431           StackLoc->MajorFunction = IRP_MJ_CREATE;
432           break;
433         
434         case CreateFileTypeNamedPipe:
435           StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
436           break;
437
438         case CreateFileTypeMailslot:
439           StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
440           break;
441      }
442    StackLoc->MinorFunction = 0;
443    StackLoc->Flags = Options;
444    StackLoc->Control = 0;
445    StackLoc->DeviceObject = FileObject->DeviceObject;
446    StackLoc->FileObject = FileObject;
447    StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
448    StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
449    StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
450    StackLoc->Parameters.Create.FileAttributes = FileAttributes;
451    StackLoc->Parameters.Create.ShareAccess = ShareAccess;
452    StackLoc->Parameters.Create.EaLength = EaLength;
453    
454    /*
455     * Now call the driver and 
456     * possibly wait if it can
457     * not complete the request
458     * immediately.
459     */
460    Status = IofCallDriver(FileObject->DeviceObject, Irp );
461    
462    if (Status == STATUS_PENDING)
463      {
464         KeWaitForSingleObject(&FileObject->Event,
465                               Executive,
466                               KernelMode,
467                               FALSE,
468                               NULL);
469         Status = IoSB.Status;
470      }
471    if (!NT_SUCCESS(Status))
472      {
473         DPRINT("Failing create request with status %x\n", Status);
474         FileObject->DeviceObject = NULL;
475         FileObject->Vpb = NULL;
476
477         ZwClose(*FileHandle);
478      }
479    if (IoStatusBlock)
480      {
481        *IoStatusBlock = IoSB;
482      }
483    assert_irql(PASSIVE_LEVEL);
484
485    DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
486
487    return (Status);
488 }
489
490 #ifndef LIBCAPTIVE
491
492 /**********************************************************************
493  * NAME                                                 EXPORTED
494  *      NtCreateFile@44
495  * 
496  * DESCRIPTION
497  *      Entry point to call IoCreateFile with
498  *      default parameters.
499  *
500  * ARGUMENTS
501  *      See IoCreateFile.
502  * 
503  * RETURN VALUE
504  *      See IoCreateFile.
505  *
506  * REVISIONS
507  *      2000-03-25 (ea)
508  *              Code originally in NtCreateFile moved in IoCreateFile.
509  */
510 NTSTATUS STDCALL
511 NtCreateFile(PHANDLE FileHandle,
512              ACCESS_MASK DesiredAccess,
513              POBJECT_ATTRIBUTES ObjectAttributes,
514              PIO_STATUS_BLOCK IoStatusBlock,
515              PLARGE_INTEGER AllocateSize,
516              ULONG FileAttributes,
517              ULONG ShareAccess,
518              ULONG CreateDisposition,
519              ULONG CreateOptions,
520              PVOID EaBuffer,
521              ULONG EaLength)
522 {
523    return IoCreateFile(FileHandle,
524                        DesiredAccess,
525                        ObjectAttributes,
526                        IoStatusBlock,
527                        AllocateSize,
528                        FileAttributes,
529                        ShareAccess,
530                        CreateDisposition,
531                        CreateOptions,
532                        EaBuffer,
533                        EaLength,
534                        CreateFileTypeNone,
535                        NULL,
536                        0);
537 }
538
539
540 /**********************************************************************
541  * NAME                                                 EXPORTED
542  *      NtOpenFile@24
543  *      
544  * DESCRIPTION
545  *      Opens an existing file (simpler than NtCreateFile).
546  *
547  * ARGUMENTS
548  *      FileHandle (OUT)
549  *              Variable that receives the file handle on return;
550  *              
551  *      DesiredAccess
552  *              Access desired by the caller to the file;
553  *              
554  *      ObjectAttributes
555  *              Structue describing the file to be opened;
556  *              
557  *      IoStatusBlock (OUT)
558  *              Receives details about the result of the
559  *              operation;
560  *              
561  *      ShareAccess
562  *              Type of shared access the caller requires;
563  *              
564  *      OpenOptions
565  *              Options for the file open.
566  *
567  * RETURN VALUE
568  *      Status.
569  *      
570  * NOTE
571  *      Undocumented.
572  */
573 NTSTATUS STDCALL
574 NtOpenFile(PHANDLE FileHandle,
575            ACCESS_MASK DesiredAccess,
576            POBJECT_ATTRIBUTES ObjectAttributes,
577            PIO_STATUS_BLOCK IoStatusBlock,
578            ULONG ShareAccess,
579            ULONG OpenOptions)
580 {
581    return IoCreateFile(FileHandle,
582                        DesiredAccess,
583                        ObjectAttributes,
584                        IoStatusBlock,
585                        NULL,
586                        0,
587                        ShareAccess,
588                        FILE_OPEN,
589                        OpenOptions,
590                        NULL,
591                        0,
592                        CreateFileTypeNone,
593                        NULL,
594                        0);
595 }
596
597 #endif /* LIBCAPTIVE */
598
599 /* EOF */