12b46d833894aff09cab8ad219631d1aa3cb30e6
[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     }
118   else
119     {
120       if ((DeviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM)
121           && (DeviceObject->DeviceType != FILE_DEVICE_DISK)
122           && (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
123           && (DeviceObject->DeviceType != FILE_DEVICE_TAPE)
124           && (DeviceObject->DeviceType != FILE_DEVICE_NETWORK)
125           && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
126           && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
127         {
128           CPRINT("Device was wrong type\n");
129           return(STATUS_UNSUCCESSFUL);
130         }
131
132       if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
133           && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
134           && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
135         {
136           if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
137             {
138               DPRINT("Mount the logical volume\n");
139               Status = IoMountVolume(DeviceObject, FALSE);
140               DPRINT("Status %x\n", Status);
141               if (!NT_SUCCESS(Status))
142                 {
143                   CPRINT("Failed to mount logical volume (Status %x)\n",
144                          Status);
145                   return(Status);
146                 }
147             }
148           DeviceObject = DeviceObject->Vpb->DeviceObject;
149           DPRINT("FsDeviceObject %lx\n", DeviceObject);
150         }
151       RtlCreateUnicodeString(&(FileObject->FileName),
152                              RemainingPath);
153     }
154
155   DPRINT("FileObject->FileName %wZ\n",
156          &FileObject->FileName);
157   FileObject->DeviceObject = DeviceObject;
158   DPRINT("FileObject %x DeviceObject %x\n",
159          FileObject,
160          DeviceObject);
161   FileObject->Vpb = DeviceObject->Vpb;
162   FileObject->Type = InternalFileType;
163   FileObject->RelatedFileObject = NULL;
164
165   return(STATUS_SUCCESS);
166 }
167
168
169 /**********************************************************************
170  * NAME                                                 EXPORTED
171  *      IoCreateStreamFileObject@8
172  *      
173  * DESCRIPTION
174  *      
175  * ARGUMENTS
176  *      FileObject
177  *              ?
178  *              
179  *      DeviceObject
180  *              ?
181  *              
182  * RETURN VALUE
183  *
184  * NOTE
185  *      
186  * REVISIONS
187  * 
188  */
189 PFILE_OBJECT STDCALL
190 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
191                          PDEVICE_OBJECT DeviceObject)
192 {
193   PFILE_OBJECT  CreatedFileObject;
194   NTSTATUS Status;
195
196   DPRINT("IoCreateStreamFileObject(FileObject %x, DeviceObject %x)\n",
197          FileObject, DeviceObject);
198
199   assert_irql(PASSIVE_LEVEL);
200
201   /* We don't need any 'Handle' therefore pass 1st parameter as NULL and it
202    * will not be created by ObCreateObject() at all.
203    */
204   Status = ObCreateObject(NULL,
205                           STANDARD_RIGHTS_REQUIRED,
206                           NULL,
207                           IoFileObjectType,
208                           (PVOID*)&CreatedFileObject);
209   if (!NT_SUCCESS(Status))
210     {
211       DPRINT("Could not create FileObject\n");
212       return (NULL);
213     }
214
215   if (FileObject != NULL)
216     {
217       DeviceObject = FileObject->DeviceObject;
218     }
219   DeviceObject = IoGetAttachedDevice(DeviceObject);
220
221   DPRINT("DeviceObject %x\n", DeviceObject);
222
223   CreatedFileObject->DeviceObject = DeviceObject->Vpb->DeviceObject;
224   CreatedFileObject->Vpb = DeviceObject->Vpb;
225   CreatedFileObject->Type = InternalFileType;
226   /* Why was FO_DIRECT_DEVICE_OPEN used here before?
227    * FO_STREAM_FILE is according to W32 documentation.
228    */
229   CreatedFileObject->Flags |= FO_STREAM_FILE;
230 #ifdef LIBCAPTIVE
231   /* We are fully single-threaded/single-processed;
232    * prevent at least IopDeleteFile()->...->IoIsOperationSynchronous() to return FALSE
233    */
234   CreatedFileObject->Flags |= FO_SYNCHRONOUS_IO;
235 #endif /* LIBCAPTIVE */
236   CreatedFileObject->FileName.Length=0;
237   CreatedFileObject->FileName.MaximumLength=0;
238   CreatedFileObject->FileName.Buffer=NULL;
239
240   // shouldn't we initialize the lock event, and several other things here too?
241   KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
242
243   return(CreatedFileObject);
244 }
245
246
247 /**********************************************************************
248  * NAME                                                 EXPORTED
249  *      IoCreateFile@56
250  *      
251  * DESCRIPTION
252  *      Either causes a new file or directory to be created, or it
253  *      opens an existing file, device, directory or volume, giving
254  *      the caller a handle for the file object. This handle can be
255  *      used by subsequent calls to manipulate data within the file
256  *      or the file object's state of attributes.
257  *      
258  * ARGUMENTS
259  *      FileHandle (OUT)
260  *              Points to a variable which receives the file handle
261  *              on return;
262  *              
263  *      DesiredAccess
264  *              Desired access to the file;
265  *              
266  *      ObjectAttributes
267  *              Structure describing the file;
268  *              
269  *      IoStatusBlock (OUT)
270  *              Receives information about the operation on return;
271  *              
272  *      AllocationSize [OPTIONAL]
273  *              Initial size of the file in bytes;
274  *              
275  *      FileAttributes
276  *              Attributes to create the file with;
277  *              
278  *      ShareAccess
279  *              Type of shared access the caller would like to the
280  *              file;
281  *              
282  *      CreateDisposition
283  *              Specifies what to do, depending on whether the
284  *              file already exists;
285  *              
286  *      CreateOptions
287  *              Options for creating a new file;
288  *              
289  *      EaBuffer [OPTIONAL]
290  *              Undocumented;
291  *              
292  *      EaLength
293  *              Undocumented;
294  *              
295  *      CreateFileType
296  *              Type of file (normal, named pipe, mailslot) to create;
297  *              
298  *      ExtraCreateParameters [OPTIONAL]
299  *              Additional creation data for named pipe and mailsots;
300  *              
301  *      Options
302  *              Undocumented.
303  *              
304  * RETURN VALUE
305  *      Status
306  *
307  * NOTE
308  *      Prototype taken from Bo Branten's ntifs.h v15.
309  *      Description taken from old NtCreateFile's which is
310  *      now a wrapper of this call.
311  *      
312  * REVISIONS
313  * 
314  */
315 NTSTATUS STDCALL
316 IoCreateFile(OUT        PHANDLE                 FileHandle,
317              IN ACCESS_MASK             DesiredAccess,
318              IN POBJECT_ATTRIBUTES      ObjectAttributes,
319              OUT        PIO_STATUS_BLOCK        IoStatusBlock,
320              IN PLARGE_INTEGER          AllocationSize          OPTIONAL,
321              IN ULONG                   FileAttributes,
322              IN ULONG                   ShareAccess,
323              IN ULONG                   CreateDisposition,
324              IN ULONG                   CreateOptions,
325              IN PVOID                   EaBuffer                OPTIONAL,
326              IN ULONG                   EaLength,
327              IN CREATE_FILE_TYPE        CreateFileType,
328              IN PVOID                   ExtraCreateParameters   OPTIONAL,
329              IN ULONG                   Options)
330 {
331    PFILE_OBJECT         FileObject;
332    NTSTATUS             Status;
333    PIRP                 Irp;
334    PIO_STACK_LOCATION   StackLoc;
335    IO_STATUS_BLOCK      IoSB;
336    IO_SECURITY_CONTEXT  SecurityContext;
337    ACCESS_STATE         AccessState;
338    
339    DPRINT("IoCreateFile(FileHandle %x, DesiredAccess %x, "
340           "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
341           FileHandle,DesiredAccess,ObjectAttributes,
342           ObjectAttributes->ObjectName->Buffer);
343    
344    assert_irql(PASSIVE_LEVEL);
345    
346    *FileHandle = 0;
347
348    Status = ObCreateObject(FileHandle,
349                            DesiredAccess,
350                            ObjectAttributes,
351                            IoFileObjectType,
352                            (PVOID*)&FileObject);
353    if (!NT_SUCCESS(Status))
354      {
355         DPRINT("ObCreateObject() failed! (Status %lx)\n", Status);
356         return(Status);
357      }
358    if (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
359      {
360         FileObject->Flags |= (FO_ALERTABLE_IO | FO_SYNCHRONOUS_IO);
361      }
362    if (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT)
363      {
364         FileObject->Flags |= FO_SYNCHRONOUS_IO;
365      }
366
367    if( CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING )
368      FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
369
370    FileObject->FsContext=NULL;
371    FileObject->FsContext2=NULL;
372
373    RtlZeroMemory(&AccessState, sizeof(AccessState));
374    AccessState.RemainingDesiredAccess=0;
375    AccessState.PreviouslyGrantedAccess=0;
376
377    SecurityContext.SecurityQos = NULL; /* ?? */
378    SecurityContext.AccessState = &AccessState;
379    SecurityContext.DesiredAccess = DesiredAccess;
380    SecurityContext.FullCreateOptions = 0; /* ?? */
381    
382    KeInitializeEvent(&FileObject->Lock, NotificationEvent, TRUE);
383    KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
384    
385    DPRINT("FileObject %x\n", FileObject);
386    DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
387    /*
388     * Create a new IRP to hand to
389     * the FS driver: this may fail
390     * due to resource shortage.
391     */
392    Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
393    if (Irp == NULL)
394      {
395         ZwClose(*FileHandle);
396         return (STATUS_UNSUCCESSFUL);
397      }
398      
399    Irp->UserIosb = &IoSB;   //return iostatus
400    Irp->AssociatedIrp.SystemBuffer = EaBuffer;
401    Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)ExtraCreateParameters;
402    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
403    Irp->UserEvent = &FileObject->Event;
404    if (AllocationSize)
405    {
406       Irp->Overlay.AllocationSize = *AllocationSize;
407    }
408    
409    /*
410     * Get the stack location for the new
411     * IRP and prepare it.
412     */
413    StackLoc = IoGetNextIrpStackLocation(Irp);
414    switch (CreateFileType)
415      {
416         default:
417         case CreateFileTypeNone:
418           StackLoc->MajorFunction = IRP_MJ_CREATE;
419           break;
420         
421         case CreateFileTypeNamedPipe:
422           StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
423           break;
424
425         case CreateFileTypeMailslot:
426           StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
427           break;
428      }
429    StackLoc->MinorFunction = 0;
430    StackLoc->Flags = Options;
431    StackLoc->Control = 0;
432    StackLoc->DeviceObject = FileObject->DeviceObject;
433    StackLoc->FileObject = FileObject;
434    StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
435    StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
436    StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
437    StackLoc->Parameters.Create.FileAttributes = FileAttributes;
438    StackLoc->Parameters.Create.ShareAccess = ShareAccess;
439    StackLoc->Parameters.Create.EaLength = EaLength;
440    
441    /*
442     * Now call the driver and 
443     * possibly wait if it can
444     * not complete the request
445     * immediately.
446     */
447    Status = IofCallDriver(FileObject->DeviceObject, Irp );
448    
449    if (Status == STATUS_PENDING)
450      {
451         KeWaitForSingleObject(&FileObject->Event,
452                               Executive,
453                               KernelMode,
454                               FALSE,
455                               NULL);
456         Status = IoSB.Status;
457      }
458    if (!NT_SUCCESS(Status))
459      {
460         DPRINT("Failing create request with status %x\n", Status);
461         FileObject->DeviceObject = NULL;
462         FileObject->Vpb = NULL;
463
464         ZwClose(*FileHandle);
465      }
466    if (IoStatusBlock)
467      {
468        *IoStatusBlock = IoSB;
469      }
470    assert_irql(PASSIVE_LEVEL);
471
472    DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
473
474    return (Status);
475 }
476
477 #ifndef LIBCAPTIVE
478
479 /**********************************************************************
480  * NAME                                                 EXPORTED
481  *      NtCreateFile@44
482  * 
483  * DESCRIPTION
484  *      Entry point to call IoCreateFile with
485  *      default parameters.
486  *
487  * ARGUMENTS
488  *      See IoCreateFile.
489  * 
490  * RETURN VALUE
491  *      See IoCreateFile.
492  *
493  * REVISIONS
494  *      2000-03-25 (ea)
495  *              Code originally in NtCreateFile moved in IoCreateFile.
496  */
497 NTSTATUS STDCALL
498 NtCreateFile(PHANDLE FileHandle,
499              ACCESS_MASK DesiredAccess,
500              POBJECT_ATTRIBUTES ObjectAttributes,
501              PIO_STATUS_BLOCK IoStatusBlock,
502              PLARGE_INTEGER AllocateSize,
503              ULONG FileAttributes,
504              ULONG ShareAccess,
505              ULONG CreateDisposition,
506              ULONG CreateOptions,
507              PVOID EaBuffer,
508              ULONG EaLength)
509 {
510    return IoCreateFile(FileHandle,
511                        DesiredAccess,
512                        ObjectAttributes,
513                        IoStatusBlock,
514                        AllocateSize,
515                        FileAttributes,
516                        ShareAccess,
517                        CreateDisposition,
518                        CreateOptions,
519                        EaBuffer,
520                        EaLength,
521                        CreateFileTypeNone,
522                        NULL,
523                        0);
524 }
525
526
527 /**********************************************************************
528  * NAME                                                 EXPORTED
529  *      NtOpenFile@24
530  *      
531  * DESCRIPTION
532  *      Opens an existing file (simpler than NtCreateFile).
533  *
534  * ARGUMENTS
535  *      FileHandle (OUT)
536  *              Variable that receives the file handle on return;
537  *              
538  *      DesiredAccess
539  *              Access desired by the caller to the file;
540  *              
541  *      ObjectAttributes
542  *              Structue describing the file to be opened;
543  *              
544  *      IoStatusBlock (OUT)
545  *              Receives details about the result of the
546  *              operation;
547  *              
548  *      ShareAccess
549  *              Type of shared access the caller requires;
550  *              
551  *      OpenOptions
552  *              Options for the file open.
553  *
554  * RETURN VALUE
555  *      Status.
556  *      
557  * NOTE
558  *      Undocumented.
559  */
560 NTSTATUS STDCALL
561 NtOpenFile(PHANDLE FileHandle,
562            ACCESS_MASK DesiredAccess,
563            POBJECT_ATTRIBUTES ObjectAttributes,
564            PIO_STATUS_BLOCK IoStatusBlock,
565            ULONG ShareAccess,
566            ULONG OpenOptions)
567 {
568    return IoCreateFile(FileHandle,
569                        DesiredAccess,
570                        ObjectAttributes,
571                        IoStatusBlock,
572                        NULL,
573                        0,
574                        ShareAccess,
575                        FILE_OPEN,
576                        OpenOptions,
577                        NULL,
578                        0,
579                        CreateFileTypeNone,
580                        NULL,
581                        0);
582 }
583
584 #endif /* LIBCAPTIVE */
585
586 /* EOF */