update for HEAD-2003091401
[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 #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 }
51
52
53 /**********************************************************************
54  * NAME                                                 INTERNAL
55  *      IopCreateFile
56  *      
57  * DESCRIPTION
58  *      
59  * ARGUMENTS
60  *              
61  * RETURN VALUE
62  *
63  * REVISIONS
64  */
65 NTSTATUS STDCALL
66 IopCreateFile(PVOID                     ObjectBody,
67               PVOID                     Parent,
68               PWSTR                     RemainingPath,
69               POBJECT_ATTRIBUTES        ObjectAttributes)
70 {
71   PDEVICE_OBJECT DeviceObject;
72   PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody;
73   POBJECT_TYPE ParentObjectType;
74   NTSTATUS Status;
75
76   DPRINT("IopCreateFile(ObjectBody %x, Parent %x, RemainingPath %S)\n",
77          ObjectBody,
78          Parent,
79          RemainingPath);
80
81   if (NULL == Parent)
82     {
83       /* This is probably an attempt to create a meta fileobject (eg. for FAT)
84          for the cache manager, so return STATUS_SUCCESS */
85       DPRINT("Parent object was NULL\n");
86       return(STATUS_SUCCESS);
87     }
88
89   ParentObjectType = BODY_TO_HEADER(Parent)->ObjectType;
90
91   if (ParentObjectType != IoDeviceObjectType &&
92       ParentObjectType != IoFileObjectType)
93     {
94       CPRINT("Parent is a %S which is neither a file type nor a device type\n",
95              BODY_TO_HEADER(Parent)->ObjectType->TypeName.Buffer);
96       return(STATUS_UNSUCCESSFUL);
97     }
98
99   Status = ObReferenceObjectByPointer(Parent,
100                                       STANDARD_RIGHTS_REQUIRED,
101                                       ParentObjectType,
102                                       UserMode);
103   if (!NT_SUCCESS(Status))
104     {
105       CPRINT("Failed to reference parent object %x\n", Parent);
106       return(Status);
107     }
108
109   if (ParentObjectType == IoDeviceObjectType)
110     {
111       /* Parent is a devce object */
112       DeviceObject = IoGetAttachedDevice((PDEVICE_OBJECT)Parent);
113       DPRINT("DeviceObject %x\n", DeviceObject);
114
115       if (RemainingPath == NULL)
116         {
117           FileObject->Flags = FileObject->Flags | FO_DIRECT_DEVICE_OPEN;
118           FileObject->FileName.Buffer = 0;
119           FileObject->FileName.Length = FileObject->FileName.MaximumLength = 0;
120         }
121       else
122         {
123           if ((DeviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM)
124               && (DeviceObject->DeviceType != FILE_DEVICE_DISK)
125               && (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
126               && (DeviceObject->DeviceType != FILE_DEVICE_TAPE)
127               && (DeviceObject->DeviceType != FILE_DEVICE_NETWORK)
128               && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
129               && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
130             {
131               CPRINT("Device was wrong type\n");
132               return(STATUS_UNSUCCESSFUL);
133             }
134
135           if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
136               && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
137               && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
138             {
139               if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
140                 {
141                   DPRINT("Mount the logical volume\n");
142                   Status = IoMountVolume(DeviceObject, FALSE);
143                   DPRINT("Status %x\n", Status);
144                   if (!NT_SUCCESS(Status))
145                     {
146                       CPRINT("Failed to mount logical volume (Status %x)\n",
147                              Status);
148                       return(Status);
149                     }
150                 }
151               DeviceObject = DeviceObject->Vpb->DeviceObject;
152               DPRINT("FsDeviceObject %lx\n", DeviceObject);
153             }
154           RtlCreateUnicodeString(&(FileObject->FileName),
155                                  RemainingPath);
156         }
157     }
158   else
159     {
160       /* Parent is a file object */
161       if (RemainingPath == NULL)
162         {
163           CPRINT("Device is unnamed\n");
164           return STATUS_UNSUCCESSFUL;
165         }
166
167       DeviceObject = ((PFILE_OBJECT)Parent)->DeviceObject;
168       DPRINT("DeviceObject %x\n", DeviceObject);
169
170       FileObject->RelatedFileObject = (PFILE_OBJECT)Parent;
171
172       RtlCreateUnicodeString(&(FileObject->FileName),
173                              RemainingPath);
174     }
175
176   DPRINT("FileObject->FileName %wZ\n",
177          &FileObject->FileName);
178   FileObject->DeviceObject = DeviceObject;
179   DPRINT("FileObject %x DeviceObject %x\n",
180          FileObject,
181          DeviceObject);
182   FileObject->Vpb = DeviceObject->Vpb;
183   FileObject->Type = InternalFileType;
184
185   return(STATUS_SUCCESS);
186 }
187
188
189 /**********************************************************************
190  * NAME                                                 EXPORTED
191  *      IoCreateStreamFileObject@8
192  *      
193  * DESCRIPTION
194  *      
195  * ARGUMENTS
196  *      FileObject
197  *              ?
198  *              
199  *      DeviceObject
200  *              ?
201  *              
202  * RETURN VALUE
203  *
204  * NOTE
205  *      
206  * REVISIONS
207  * 
208  * @implemented
209  */
210 PFILE_OBJECT STDCALL
211 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
212                          PDEVICE_OBJECT DeviceObject)
213 {
214   HANDLE                FileHandle;
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 = ObRosCreateObject(&FileHandle,
224                           STANDARD_RIGHTS_REQUIRED,
225                           NULL,
226                           IoFileObjectType,
227                           (PVOID*)&CreatedFileObject);
228   if (!NT_SUCCESS(Status))
229     {
230       DPRINT("Could not create FileObject\n");
231       return (NULL);
232     }
233
234   if (FileObject != NULL)
235     {
236       DeviceObject = FileObject->DeviceObject;
237     }
238   DeviceObject = IoGetAttachedDevice(DeviceObject);
239
240   DPRINT("DeviceObject %x\n", DeviceObject);
241
242   CreatedFileObject->DeviceObject = DeviceObject->Vpb->DeviceObject;
243   CreatedFileObject->Vpb = DeviceObject->Vpb;
244   CreatedFileObject->Type = InternalFileType;
245   CreatedFileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
246
247   // shouldn't we initialize the lock event, and several other things here too?
248   KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
249
250   ZwClose(FileHandle);
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  * @implemented
324  */
325 NTSTATUS STDCALL
326 IoCreateFile(OUT        PHANDLE                 FileHandle,
327              IN ACCESS_MASK             DesiredAccess,
328              IN POBJECT_ATTRIBUTES      ObjectAttributes,
329              OUT        PIO_STATUS_BLOCK        IoStatusBlock,
330              IN PLARGE_INTEGER          AllocationSize          OPTIONAL,
331              IN ULONG                   FileAttributes,
332              IN ULONG                   ShareAccess,
333              IN ULONG                   CreateDisposition,
334              IN ULONG                   CreateOptions,
335              IN PVOID                   EaBuffer                OPTIONAL,
336              IN ULONG                   EaLength,
337              IN CREATE_FILE_TYPE        CreateFileType,
338              IN PVOID                   ExtraCreateParameters   OPTIONAL,
339              IN ULONG                   Options)
340 {
341    PFILE_OBJECT         FileObject;
342    NTSTATUS             Status;
343    PIRP                 Irp;
344    PIO_STACK_LOCATION   StackLoc;
345    IO_STATUS_BLOCK      IoSB;
346    IO_SECURITY_CONTEXT  SecurityContext;
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 = ObRosCreateObject(FileHandle,
358                            DesiredAccess,
359                            ObjectAttributes,
360                            IoFileObjectType,
361                            (PVOID*)&FileObject);
362    if (!NT_SUCCESS(Status))
363      {
364         DPRINT("ObRosCreateObject() 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    SecurityContext.SecurityQos = NULL; /* ?? */
380    SecurityContext.AccessState = NULL; /* ?? */
381    SecurityContext.DesiredAccess = DesiredAccess;
382    SecurityContext.FullCreateOptions = 0; /* ?? */
383    
384    KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, TRUE);
385    KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
386    
387    DPRINT("FileObject %x\n", FileObject);
388    DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
389    /*
390     * Create a new IRP to hand to
391     * the FS driver: this may fail
392     * due to resource shortage.
393     */
394    Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
395    if (Irp == NULL)
396      {
397         ZwClose(*FileHandle);
398         return (STATUS_UNSUCCESSFUL);
399      }
400
401    //trigger FileObject/Event dereferencing
402    Irp->Tail.Overlay.OriginalFileObject = FileObject;
403      
404    Irp->UserIosb = &IoSB;   //return iostatus
405    Irp->AssociatedIrp.SystemBuffer = EaBuffer;
406    Irp->Tail.Overlay.AuxiliaryBuffer = (PCHAR)ExtraCreateParameters;
407    Irp->Tail.Overlay.Thread = PsGetCurrentThread();
408    Irp->UserEvent = &FileObject->Event;
409    if (AllocationSize)
410    {
411       Irp->Overlay.AllocationSize = *AllocationSize;
412    }
413    
414    /*
415     * Get the stack location for the new
416     * IRP and prepare it.
417     */
418    StackLoc = IoGetNextIrpStackLocation(Irp);
419    switch (CreateFileType)
420      {
421         default:
422         case CreateFileTypeNone:
423           StackLoc->MajorFunction = IRP_MJ_CREATE;
424           break;
425         
426         case CreateFileTypeNamedPipe:
427           StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
428           break;
429
430         case CreateFileTypeMailslot:
431           StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
432           break;
433      }
434    StackLoc->MinorFunction = 0;
435    StackLoc->Flags = Options;
436    StackLoc->Control = 0;
437    StackLoc->DeviceObject = FileObject->DeviceObject;
438    StackLoc->FileObject = FileObject;
439    StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
440    StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
441    StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
442    StackLoc->Parameters.Create.FileAttributes = FileAttributes;
443    StackLoc->Parameters.Create.ShareAccess = ShareAccess;
444    StackLoc->Parameters.Create.EaLength = EaLength;
445    
446    /*
447     * Now call the driver and 
448     * possibly wait if it can
449     * not complete the request
450     * immediately.
451     */
452    Status = IofCallDriver(FileObject->DeviceObject, Irp );
453    
454    if (Status == STATUS_PENDING)
455      {
456         KeWaitForSingleObject(&FileObject->Event,
457                               Executive,
458                               KernelMode,
459                               FALSE,
460                               NULL);
461         Status = IoSB.Status;
462      }
463    if (!NT_SUCCESS(Status))
464      {
465         DPRINT("Failing create request with status %x\n", Status);
466         FileObject->DeviceObject = NULL;
467         FileObject->Vpb = NULL;
468
469         ZwClose(*FileHandle);
470      }
471    if (IoStatusBlock)
472      {
473        *IoStatusBlock = IoSB;
474      }
475    assert_irql(PASSIVE_LEVEL);
476
477    DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
478
479    return (Status);
480 }
481
482
483 /**********************************************************************
484  * NAME                                                 EXPORTED
485  *      NtCreateFile@44
486  * 
487  * DESCRIPTION
488  *      Entry point to call IoCreateFile with
489  *      default parameters.
490  *
491  * ARGUMENTS
492  *      See IoCreateFile.
493  * 
494  * RETURN VALUE
495  *      See IoCreateFile.
496  *
497  * REVISIONS
498  *      2000-03-25 (ea)
499  *              Code originally in NtCreateFile moved in IoCreateFile.
500  *
501  * @implemented
502  */
503 NTSTATUS STDCALL
504 NtCreateFile(PHANDLE FileHandle,
505              ACCESS_MASK DesiredAccess,
506              POBJECT_ATTRIBUTES ObjectAttributes,
507              PIO_STATUS_BLOCK IoStatusBlock,
508              PLARGE_INTEGER AllocateSize,
509              ULONG FileAttributes,
510              ULONG ShareAccess,
511              ULONG CreateDisposition,
512              ULONG CreateOptions,
513              PVOID EaBuffer,
514              ULONG EaLength)
515 {
516    return IoCreateFile(FileHandle,
517                        DesiredAccess,
518                        ObjectAttributes,
519                        IoStatusBlock,
520                        AllocateSize,
521                        FileAttributes,
522                        ShareAccess,
523                        CreateDisposition,
524                        CreateOptions,
525                        EaBuffer,
526                        EaLength,
527                        CreateFileTypeNone,
528                        NULL,
529                        0);
530 }
531
532
533 /**********************************************************************
534  * NAME                                                 EXPORTED
535  *      NtOpenFile@24
536  *      
537  * DESCRIPTION
538  *      Opens an existing file (simpler than NtCreateFile).
539  *
540  * ARGUMENTS
541  *      FileHandle (OUT)
542  *              Variable that receives the file handle on return;
543  *              
544  *      DesiredAccess
545  *              Access desired by the caller to the file;
546  *              
547  *      ObjectAttributes
548  *              Structue describing the file to be opened;
549  *              
550  *      IoStatusBlock (OUT)
551  *              Receives details about the result of the
552  *              operation;
553  *              
554  *      ShareAccess
555  *              Type of shared access the caller requires;
556  *              
557  *      OpenOptions
558  *              Options for the file open.
559  *
560  * RETURN VALUE
561  *      Status.
562  *      
563  * NOTE
564  *      Undocumented.
565  *
566  * @implemented
567  */
568 NTSTATUS STDCALL
569 NtOpenFile(PHANDLE FileHandle,
570            ACCESS_MASK DesiredAccess,
571            POBJECT_ATTRIBUTES ObjectAttributes,
572            PIO_STATUS_BLOCK IoStatusBlock,
573            ULONG ShareAccess,
574            ULONG OpenOptions)
575 {
576    return IoCreateFile(FileHandle,
577                        DesiredAccess,
578                        ObjectAttributes,
579                        IoStatusBlock,
580                        NULL,
581                        0,
582                        ShareAccess,
583                        FILE_OPEN,
584                        OpenOptions,
585                        NULL,
586                        0,
587                        CreateFileTypeNone,
588                        NULL,
589                        0);
590 }
591
592 /* EOF */