xref: /reactos/ntoskrnl/io/iomgr/file.c (revision f4d29a74)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/io/iomgr/file.c
5  * PURPOSE:         Functions that deal with managing the FILE_OBJECT itself.
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  *                  Gunnar Dalsnes
8  *                  Eric Kohl
9  *                  Filip Navara (navaraf@reactos.org)
10  *                  Pierre Schweitzer
11  */
12 
13 /* INCLUDES *****************************************************************/
14 
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <debug.h>
18 
19 extern ERESOURCE IopSecurityResource;
20 
21 /* PRIVATE FUNCTIONS *********************************************************/
22 
23 VOID
24 NTAPI
25 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,
26                                IN OUT PULONG CreateOptions,
27                                IN KPROCESSOR_MODE PreviousMode,
28                                IN ULONG Disposition)
29 {
30     ACCESS_MASK DesiredAccess, ReadAccess, WriteAccess;
31     PRIVILEGE_SET Privileges;
32     BOOLEAN AccessGranted, HaveBackupPriv = FALSE, CheckRestore = FALSE;
33     PAGED_CODE();
34 
35     /* Don't do anything if privileges were checked already */
36     if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) return;
37 
38     /* Check if the file was actually opened for backup purposes */
39     if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
40     {
41         /* Set the check flag since were doing it now */
42         AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
43 
44         /* Set the access masks required */
45         ReadAccess = READ_CONTROL |
46                      ACCESS_SYSTEM_SECURITY |
47                      FILE_GENERIC_READ |
48                      FILE_TRAVERSE;
49         WriteAccess = WRITE_DAC |
50                       WRITE_OWNER |
51                       ACCESS_SYSTEM_SECURITY |
52                       FILE_GENERIC_WRITE |
53                       FILE_ADD_FILE |
54                       FILE_ADD_SUBDIRECTORY |
55                       DELETE;
56         DesiredAccess = AccessState->RemainingDesiredAccess;
57 
58         /* Check if desired access was the maximum */
59         if (DesiredAccess & MAXIMUM_ALLOWED)
60         {
61             /* Then add all the access masks required */
62             DesiredAccess |= (ReadAccess | WriteAccess);
63         }
64 
65         /* Check if the file already exists */
66         if (Disposition & FILE_OPEN)
67         {
68             /* Check if desired access has the read mask */
69             if (ReadAccess & DesiredAccess)
70             {
71                 /* Setup the privilege check lookup */
72                 Privileges.PrivilegeCount = 1;
73                 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
74                 Privileges.Privilege[0].Luid = SeBackupPrivilege;
75                 Privileges.Privilege[0].Attributes = 0;
76                 AccessGranted = SePrivilegeCheck(&Privileges,
77                                                  &AccessState->
78                                                  SubjectSecurityContext,
79                                                  PreviousMode);
80                 if (AccessGranted)
81                 {
82                     /* Remember that backup was allowed */
83                     HaveBackupPriv = TRUE;
84 
85                     /* Append the privileges and update the access state */
86                     SeAppendPrivileges(AccessState, &Privileges);
87                     AccessState->PreviouslyGrantedAccess |= (DesiredAccess & ReadAccess);
88                     AccessState->RemainingDesiredAccess &= ~ReadAccess;
89                     DesiredAccess &= ~ReadAccess;
90 
91                     /* Set backup privilege for the token */
92                     AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
93                 }
94             }
95         }
96         else
97         {
98             /* Caller is creating the file, check restore privileges later */
99             CheckRestore = TRUE;
100         }
101 
102         /* Check if caller wants write access or if it's creating a file */
103         if ((WriteAccess & DesiredAccess) || (CheckRestore))
104         {
105             /* Setup the privilege lookup and do it */
106             Privileges.PrivilegeCount = 1;
107             Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
108             Privileges.Privilege[0].Luid = SeRestorePrivilege;
109             Privileges.Privilege[0].Attributes = 0;
110             AccessGranted = SePrivilegeCheck(&Privileges,
111                                              &AccessState->SubjectSecurityContext,
112                                              PreviousMode);
113             if (AccessGranted)
114             {
115                 /* Remember that privilege was given */
116                 HaveBackupPriv = TRUE;
117 
118                 /* Append the privileges and update the access state */
119                 SeAppendPrivileges(AccessState, &Privileges);
120                 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & WriteAccess);
121                 AccessState->RemainingDesiredAccess &= ~WriteAccess;
122 
123                 /* Set restore privilege for the token */
124                 AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
125             }
126         }
127 
128         /* If we don't have the privilege, remove the option */
129         if (!HaveBackupPriv) *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
130     }
131 }
132 
133 NTSTATUS
134 NTAPI
135 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
136                         IN PDEVICE_OBJECT DeviceObject)
137 {
138     /* Make sure the object is valid */
139     if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
140         (DOE_UNLOAD_PENDING |
141          DOE_DELETE_PENDING |
142          DOE_REMOVE_PENDING |
143          DOE_REMOVE_PROCESSED)) ||
144         (DeviceObject->Flags & DO_DEVICE_INITIALIZING))
145     {
146         /* It's unloading or initializing, so fail */
147         DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
148                 " sucks. Please fix it's AddDevice Routine\n",
149                 &DeviceObject->DriverObject->DriverName);
150         return STATUS_NO_SUCH_DEVICE;
151     }
152     else if ((DeviceObject->Flags & DO_EXCLUSIVE) &&
153              (DeviceObject->ReferenceCount) &&
154              !(OpenPacket->RelatedFileObject) &&
155              !(OpenPacket->Options & IO_ATTACH_DEVICE))
156     {
157         return STATUS_ACCESS_DENIED;
158     }
159 
160     else
161     {
162         /* Increase reference count */
163         InterlockedIncrement(&DeviceObject->ReferenceCount);
164         return STATUS_SUCCESS;
165     }
166 }
167 
168 VOID
169 NTAPI
170 IopDoNameTransmogrify(IN PIRP Irp,
171                       IN PFILE_OBJECT FileObject,
172                       IN PREPARSE_DATA_BUFFER DataBuffer)
173 {
174     PWSTR Buffer;
175     USHORT Length;
176     USHORT RequiredLength;
177     PWSTR NewBuffer;
178 
179     PAGED_CODE();
180 
181     ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
182     ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
183     ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
184     ASSERT(DataBuffer != NULL);
185     ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
186     ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
187     ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
188 
189     /* First of all, validate data */
190     if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
191         (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
192          DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
193          FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
194     {
195         Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
196     }
197 
198     /* Everything went right */
199     if (NT_SUCCESS(Irp->IoStatus.Status))
200     {
201         /* Compute buffer & length */
202         Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
203                                     DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
204         Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
205 
206         /* Check we don't overflow */
207         if (((ULONG)MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
208         {
209             Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
210         }
211         else
212         {
213             /* Compute how much mem we'll need */
214             RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
215 
216             /* Check if FileObject can already hold what we need */
217             if (FileObject->FileName.MaximumLength >= RequiredLength)
218             {
219                 NewBuffer = FileObject->FileName.Buffer;
220             }
221             else
222             {
223                 /* Allocate otherwise */
224                 NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
225                 if (NewBuffer == NULL)
226                 {
227                      Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
228                 }
229             }
230         }
231     }
232 
233     /* Everything went right */
234     if (NT_SUCCESS(Irp->IoStatus.Status))
235     {
236         /* Copy reserved */
237         if (DataBuffer->Reserved)
238         {
239             RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
240                           (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
241                           DataBuffer->Reserved);
242         }
243 
244         /* Then, buffer */
245         if (Length)
246         {
247             RtlCopyMemory(NewBuffer, Buffer, Length);
248         }
249 
250         /* And finally replace buffer if new one was allocated */
251         FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
252         if (NewBuffer != FileObject->FileName.Buffer)
253         {
254             if (FileObject->FileName.Buffer)
255             {
256                 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
257             }
258 
259             FileObject->FileName.Buffer = NewBuffer;
260             FileObject->FileName.MaximumLength = RequiredLength;
261             FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
262         }
263     }
264 
265     /* We don't need them anymore - it was allocated by the driver */
266     ExFreePool(DataBuffer);
267 }
268 
269 NTSTATUS
270 IopCheckTopDeviceHint(IN OUT PDEVICE_OBJECT * DeviceObject,
271                       IN POPEN_PACKET OpenPacket,
272                       BOOLEAN DirectOpen)
273 {
274     PDEVICE_OBJECT LocalDevice;
275     DEVICE_TYPE DeviceType;
276 
277     LocalDevice = *DeviceObject;
278 
279     /* Direct open is not allowed */
280     if (DirectOpen)
281     {
282         return STATUS_INVALID_PARAMETER;
283     }
284 
285     /* Validate we have a file system device */
286     DeviceType = LocalDevice->DeviceType;
287     if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
288         DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
289         DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
290         DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
291         DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
292     {
293         return STATUS_INVALID_PARAMETER;
294     }
295 
296     /* Verify the hint and if it's OK, return it */
297     if (IopVerifyDeviceObjectOnStack(LocalDevice, OpenPacket->TopDeviceObjectHint))
298     {
299         *DeviceObject = OpenPacket->TopDeviceObjectHint;
300         return STATUS_SUCCESS;
301     }
302 
303     /* Failure case here */
304     /* If we thought was had come through a mount point,
305      * actually update we didn't and return the error
306      */
307     if (OpenPacket->TraversedMountPoint)
308     {
309         OpenPacket->TraversedMountPoint = FALSE;
310         return STATUS_MOUNT_POINT_NOT_RESOLVED;
311     }
312 
313     /* Otherwise, just return the fact the hint is invalid */
314     return STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
315 }
316 
317 NTSTATUS
318 NTAPI
319 IopParseDevice(IN PVOID ParseObject,
320                IN PVOID ObjectType,
321                IN OUT PACCESS_STATE AccessState,
322                IN KPROCESSOR_MODE AccessMode,
323                IN ULONG Attributes,
324                IN OUT PUNICODE_STRING CompleteName,
325                IN OUT PUNICODE_STRING RemainingName,
326                IN OUT PVOID Context,
327                IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
328                OUT PVOID *Object)
329 {
330     POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
331     PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
332     PDEVICE_OBJECT DeviceObject, OwnerDevice;
333     NTSTATUS Status;
334     PFILE_OBJECT FileObject;
335     PVPB Vpb = NULL;
336     PIRP Irp;
337     PIO_STACK_LOCATION StackLoc;
338     IO_SECURITY_CONTEXT SecurityContext;
339     IO_STATUS_BLOCK IoStatusBlock;
340     BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
341     OBJECT_ATTRIBUTES ObjectAttributes;
342     KIRQL OldIrql;
343     PDUMMY_FILE_OBJECT LocalFileObject;
344     PFILE_BASIC_INFORMATION FileBasicInfo;
345     ULONG ReturnLength;
346     KPROCESSOR_MODE CheckMode;
347     BOOLEAN VolumeOpen = FALSE;
348     ACCESS_MASK DesiredAccess, GrantedAccess;
349     BOOLEAN AccessGranted, LockHeld = FALSE;
350     PPRIVILEGE_SET Privileges = NULL;
351     UNICODE_STRING FileString;
352     USHORT Attempt;
353     IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
354             ParseObject, RemainingName);
355 
356     for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
357     {
358         /* Assume failure */
359         *Object = NULL;
360 
361         /* Validate the open packet */
362         if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
363 
364         /* Valide reparse point in case we traversed a mountpoint */
365         if (OpenPacket->TraversedMountPoint)
366         {
367             /* This is a reparse point we understand */
368             ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
369 
370             /* Make sure we're dealing with correct DO */
371             if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
372                 OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
373                 OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
374                 OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
375             {
376                 OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
377                 return STATUS_IO_REPARSE_DATA_INVALID;
378             }
379         }
380 
381         /* Check if we have a related file object */
382         if (OpenPacket->RelatedFileObject)
383         {
384             /* Use the related file object's device object */
385             OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
386         }
387 
388         /* Validate device status */
389         Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
390         if (!NT_SUCCESS(Status))
391         {
392             /* We failed, return status */
393             OpenPacket->FinalStatus = Status;
394             return Status;
395         }
396 
397         /* Map the generic mask and set the new mapping in the access state */
398         RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
399                           &IoFileObjectType->TypeInfo.GenericMapping);
400         RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
401                           &IoFileObjectType->TypeInfo.GenericMapping);
402         SeSetAccessStateGenericMapping(AccessState,
403                                        &IoFileObjectType->TypeInfo.GenericMapping);
404         DesiredAccess = AccessState->RemainingDesiredAccess;
405 
406         /* Check what kind of access checks to do */
407         if ((AccessMode != KernelMode) ||
408             (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
409         {
410             /* Call is from user-mode or kernel is forcing checks */
411             CheckMode = UserMode;
412         }
413         else
414         {
415             /* Call is from the kernel */
416             CheckMode = KernelMode;
417         }
418 
419         /* Check privilege for backup or restore operation */
420         IopCheckBackupRestorePrivilege(AccessState,
421                                        &OpenPacket->CreateOptions,
422                                        CheckMode,
423                                        OpenPacket->Disposition);
424 
425         /* Check if we are re-parsing */
426         if (((OpenPacket->Override) && !(RemainingName->Length)) ||
427             (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
428         {
429             /* Get granted access from the last call */
430             DesiredAccess |= AccessState->PreviouslyGrantedAccess;
431         }
432 
433         /* Check if this is a volume open */
434         if ((OpenPacket->RelatedFileObject) &&
435             (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
436             !(RemainingName->Length))
437         {
438             /* It is */
439             VolumeOpen = TRUE;
440         }
441 
442         /* Now check if we need access checks */
443         if (((AccessMode != KernelMode) ||
444              (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
445             (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
446             !(OpenPacket->Override))
447         {
448             KeEnterCriticalRegion();
449             ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
450 
451             /* Check if a device object is being parsed  */
452             if (!RemainingName->Length)
453             {
454                 /* Lock the subject context */
455                 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
456                 LockHeld = TRUE;
457 
458                 /* Do access check */
459                 AccessGranted = SeAccessCheck(OriginalDeviceObject->
460                                               SecurityDescriptor,
461                                               &AccessState->SubjectSecurityContext,
462                                               LockHeld,
463                                               DesiredAccess,
464                                               0,
465                                               &Privileges,
466                                               &IoFileObjectType->
467                                               TypeInfo.GenericMapping,
468                                               UserMode,
469                                               &GrantedAccess,
470                                               &Status);
471                 if (Privileges)
472                 {
473                     /* Append and free the privileges */
474                     SeAppendPrivileges(AccessState, Privileges);
475                     SeFreePrivileges(Privileges);
476                 }
477 
478                 /* Check if we got access */
479                 if (AccessGranted)
480                 {
481                     /* Update access state */
482                     AccessState->PreviouslyGrantedAccess |= GrantedAccess;
483                     AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
484                                                              MAXIMUM_ALLOWED);
485                     OpenPacket->Override= TRUE;
486                 }
487 
488                 FileString.Length = 8;
489                 FileString.MaximumLength = 8;
490                 FileString.Buffer = L"File";
491 
492                 /* Do Audit/Alarm for open operation */
493                 SeOpenObjectAuditAlarm(&FileString,
494                                        OriginalDeviceObject,
495                                        CompleteName,
496                                        OriginalDeviceObject->SecurityDescriptor,
497                                        AccessState,
498                                        FALSE,
499                                        AccessGranted,
500                                        UserMode,
501                                        &AccessState->GenerateOnClose);
502             }
503             else
504             {
505                 /* Check if we need to do traverse validation */
506                 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
507                     ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
508                      (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
509                 {
510                     /* Check if this is a restricted token */
511                     if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
512                     {
513                         /* Do the FAST traverse check */
514                         AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
515                                                             AccessState,
516                                                             FILE_TRAVERSE,
517                                                             UserMode);
518                     }
519                     else
520                     {
521                         /* Fail */
522                         AccessGranted = FALSE;
523                     }
524 
525                     /* Check if we failed to get access */
526                     if (!AccessGranted)
527                     {
528                         /* Lock the subject context */
529                         SeLockSubjectContext(&AccessState->SubjectSecurityContext);
530                         LockHeld = TRUE;
531 
532                         /* Do access check */
533                         AccessGranted = SeAccessCheck(OriginalDeviceObject->
534                                                       SecurityDescriptor,
535                                                       &AccessState->SubjectSecurityContext,
536                                                       LockHeld,
537                                                       FILE_TRAVERSE,
538                                                       0,
539                                                       &Privileges,
540                                                       &IoFileObjectType->
541                                                       TypeInfo.GenericMapping,
542                                                       UserMode,
543                                                       &GrantedAccess,
544                                                       &Status);
545                         if (Privileges)
546                         {
547                             /* Append and free the privileges */
548                             SeAppendPrivileges(AccessState, Privileges);
549                             SeFreePrivileges(Privileges);
550                         }
551                     }
552 
553                     /* FIXME: Do Audit/Alarm for traverse check */
554                 }
555                 else
556                 {
557                     /* Access automatically granted */
558                     AccessGranted = TRUE;
559                 }
560             }
561 
562             ExReleaseResourceLite(&IopSecurityResource);
563             KeLeaveCriticalRegion();
564 
565             /* Check if we hold the lock */
566             if (LockHeld)
567             {
568                 /* Release it */
569                 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
570             }
571 
572             /* Check if access failed */
573             if (!AccessGranted)
574             {
575                 /* Dereference the device and fail */
576                 DPRINT1("Traverse access failed!\n");
577                 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
578                 return STATUS_ACCESS_DENIED;
579             }
580         }
581 
582         /* Check if we can simply use a dummy file */
583         UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
584 
585         /* Check if this is a direct open */
586         if (!(RemainingName->Length) &&
587             !(OpenPacket->RelatedFileObject) &&
588             ((DesiredAccess & ~(SYNCHRONIZE |
589                                 FILE_READ_ATTRIBUTES |
590                                 READ_CONTROL |
591                                 ACCESS_SYSTEM_SECURITY |
592                                 WRITE_OWNER |
593                                 WRITE_DAC)) == 0) &&
594             !(UseDummyFile))
595         {
596             /* Remember this for later */
597             DirectOpen = TRUE;
598         }
599 
600         /* Check if we have a related FO that wasn't a direct open */
601         if ((OpenPacket->RelatedFileObject) &&
602             !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
603         {
604             /* The device object is the one we were given */
605             DeviceObject = ParseObject;
606 
607             /* Check if the related FO had a VPB */
608             if (OpenPacket->RelatedFileObject->Vpb)
609             {
610                 /* Yes, remember it */
611                 Vpb = OpenPacket->RelatedFileObject->Vpb;
612 
613                 /* Reference it */
614                 InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
615 
616                 /* Check if we were given a specific top level device to use */
617                 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
618                 {
619                     DeviceObject = Vpb->DeviceObject;
620                 }
621             }
622         }
623         else
624         {
625             /* Check if it has a VPB */
626             if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
627             {
628                 /* Check if the VPB is mounted, and mount it */
629                 Vpb = IopCheckVpbMounted(OpenPacket,
630                                          OriginalDeviceObject,
631                                          RemainingName,
632                                          &Status);
633                 if (!Vpb) return Status;
634 
635                 /* Get the VPB's device object */
636                 DeviceObject = Vpb->DeviceObject;
637             }
638             else
639             {
640                 /* The device object is the one we were given */
641                 DeviceObject = OriginalDeviceObject;
642             }
643 
644             /* If we weren't given a specific top level device, look for an attached device */
645             if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
646                 DeviceObject->AttachedDevice)
647             {
648                 /* Get the attached device */
649                 DeviceObject = IoGetAttachedDevice(DeviceObject);
650             }
651         }
652 
653         /* If we have a top level device hint, verify it */
654         if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
655         {
656             Status = IopCheckTopDeviceHint(&DeviceObject, OpenPacket, DirectOpen);
657             if (!NT_SUCCESS(Status))
658             {
659                 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
660                 if (Vpb) IopDereferenceVpbAndFree(Vpb);
661                 return Status;
662             }
663         }
664 
665         /* If we traversed a mount point, reset the information */
666         if (OpenPacket->TraversedMountPoint)
667         {
668             OpenPacket->TraversedMountPoint = FALSE;
669         }
670 
671         /* Check if this is a secure FSD */
672         if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
673             ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
674             (!VolumeOpen))
675         {
676             Privileges = NULL;
677             GrantedAccess = 0;
678 
679             KeEnterCriticalRegion();
680             ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
681 
682             /* Lock the subject context */
683             SeLockSubjectContext(&AccessState->SubjectSecurityContext);
684 
685             /* Do access check */
686             AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
687                                           &AccessState->SubjectSecurityContext,
688                                           TRUE,
689                                           DesiredAccess,
690                                           0,
691                                           &Privileges,
692                                           &IoFileObjectType->TypeInfo.GenericMapping,
693                                           UserMode,
694                                           &GrantedAccess,
695                                           &Status);
696             if (Privileges != NULL)
697             {
698                 /* Append and free the privileges */
699                 SeAppendPrivileges(AccessState, Privileges);
700                 SeFreePrivileges(Privileges);
701             }
702 
703             /* Check if we got access */
704             if (GrantedAccess)
705             {
706                 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
707                 AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
708             }
709 
710             FileString.Length = 8;
711             FileString.MaximumLength = 8;
712             FileString.Buffer = L"File";
713 
714             /* Do Audit/Alarm for open operation
715              * NOTA: we audit target device object
716              */
717             SeOpenObjectAuditAlarm(&FileString,
718                                    DeviceObject,
719                                    CompleteName,
720                                    OriginalDeviceObject->SecurityDescriptor,
721                                    AccessState,
722                                    FALSE,
723                                    AccessGranted,
724                                    UserMode,
725                                    &AccessState->GenerateOnClose);
726 
727             SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
728 
729             ExReleaseResourceLite(&IopSecurityResource);
730             KeLeaveCriticalRegion();
731 
732             /* Check if access failed */
733             if (!AccessGranted)
734             {
735                 /* Dereference the device and fail */
736                 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
737                 if (Vpb) IopDereferenceVpbAndFree(Vpb);
738                 return STATUS_ACCESS_DENIED;
739             }
740         }
741 
742         /* Allocate the IRP */
743         Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
744         if (!Irp)
745         {
746             /* Dereference the device and VPB, then fail */
747             IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
748             if (Vpb) IopDereferenceVpbAndFree(Vpb);
749             return STATUS_INSUFFICIENT_RESOURCES;
750         }
751 
752         /* Now set the IRP data */
753         Irp->RequestorMode = AccessMode;
754         Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
755         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
756         Irp->UserIosb = &IoStatusBlock;
757         Irp->MdlAddress = NULL;
758         Irp->PendingReturned = FALSE;
759         Irp->UserEvent = NULL;
760         Irp->Cancel = FALSE;
761         Irp->CancelRoutine = NULL;
762         Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
763 
764         /* Setup the security context */
765         SecurityContext.SecurityQos = SecurityQos;
766         SecurityContext.AccessState = AccessState;
767         SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
768         SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
769 
770         /* Get the I/O Stack location */
771         StackLoc = IoGetNextIrpStackLocation(Irp);
772         StackLoc->Control = 0;
773 
774         /* Check what kind of file this is */
775         switch (OpenPacket->CreateFileType)
776         {
777             /* Normal file */
778             case CreateFileTypeNone:
779 
780                 /* Set the major function and EA Length */
781                 StackLoc->MajorFunction = IRP_MJ_CREATE;
782                 StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
783 
784                 /* Set the flags */
785                 StackLoc->Flags = (UCHAR)OpenPacket->Options;
786                 StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
787                 break;
788 
789             /* Named pipe */
790             case CreateFileTypeNamedPipe:
791 
792                 /* Set the named pipe MJ and set the parameters */
793                 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
794                 StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
795                 break;
796 
797             /* Mailslot */
798             case CreateFileTypeMailslot:
799 
800                 /* Set the mailslot MJ and set the parameters */
801                 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
802                 StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
803                 break;
804         }
805 
806         /* Set the common data */
807         Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
808         Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
809         StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
810                                               (OpenPacket->CreateOptions &
811                                                0xFFFFFF);
812         StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
813         StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
814         StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
815 
816         /* Check if we really need to create an object */
817         if (!UseDummyFile)
818         {
819             ULONG ObjectSize = sizeof(FILE_OBJECT);
820 
821             /* Tag on space for a file object extension */
822             if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
823                 ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
824 
825             /* Create the actual file object */
826             InitializeObjectAttributes(&ObjectAttributes,
827                                        NULL,
828                                        Attributes,
829                                        NULL,
830                                        NULL);
831             Status = ObCreateObject(KernelMode,
832                                     IoFileObjectType,
833                                     &ObjectAttributes,
834                                     AccessMode,
835                                     NULL,
836                                     ObjectSize,
837                                     0,
838                                     0,
839                                     (PVOID*)&FileObject);
840             if (!NT_SUCCESS(Status))
841             {
842                 /* Create failed, free the IRP */
843                 IoFreeIrp(Irp);
844 
845                 /* Dereference the device and VPB */
846                 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
847                 if (Vpb) IopDereferenceVpbAndFree(Vpb);
848 
849                 /* We failed, return status */
850                 OpenPacket->FinalStatus = Status;
851                 return Status;
852             }
853 
854             /* Clear the file object */
855             RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
856 
857             /* Check if this is Synch I/O */
858             if (OpenPacket->CreateOptions &
859                 (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
860             {
861                 /* Set the synch flag */
862                 FileObject->Flags |= FO_SYNCHRONOUS_IO;
863 
864                 /* Check if it's also alertable */
865                 if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
866                 {
867                     /* It is, set the alertable flag */
868                     FileObject->Flags |= FO_ALERTABLE_IO;
869                 }
870             }
871 
872             /* Check if this is synch I/O */
873             if (FileObject->Flags & FO_SYNCHRONOUS_IO)
874             {
875                 /* Initialize the event */
876                 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
877             }
878 
879             /* Check if the caller requested no intermediate buffering */
880             if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
881             {
882                 /* Set the correct flag for the FSD to read */
883                 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
884             }
885 
886             /* Check if the caller requested write through support */
887             if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
888             {
889                 /* Set the correct flag for the FSD to read */
890                 FileObject->Flags |= FO_WRITE_THROUGH;
891             }
892 
893             /* Check if the caller says the file will be only read sequentially */
894             if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
895             {
896                 /* Set the correct flag for the FSD to read */
897                 FileObject->Flags |= FO_SEQUENTIAL_ONLY;
898             }
899 
900             /* Check if the caller believes the file will be only read randomly */
901             if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
902             {
903                 /* Set the correct flag for the FSD to read */
904                 FileObject->Flags |= FO_RANDOM_ACCESS;
905             }
906 
907             /* Check if we were asked to setup a file object extension */
908             if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
909             {
910                 PFILE_OBJECT_EXTENSION FileObjectExtension;
911 
912                 /* Make sure the file object knows it has an extension */
913                 FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
914 
915                 FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
916                 FileObject->FileObjectExtension = FileObjectExtension;
917 
918                 /* Add the top level device which we'll send the request to */
919                 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
920                 {
921                     FileObjectExtension->TopDeviceObjectHint = DeviceObject;
922                 }
923             }
924         }
925         else
926         {
927             /* Use the dummy object instead */
928             LocalFileObject = OpenPacket->LocalFileObject;
929             RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
930 
931             /* Set it up */
932             FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
933             LocalFileObject->ObjectHeader.Type = IoFileObjectType;
934             LocalFileObject->ObjectHeader.PointerCount = 1;
935         }
936 
937         /* Setup the file header */
938         FileObject->Type = IO_TYPE_FILE;
939         FileObject->Size = sizeof(FILE_OBJECT);
940         FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
941         FileObject->DeviceObject = OriginalDeviceObject;
942 
943         /* Check if this is a direct device open */
944         if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
945 
946         /* Check if the caller wants case sensitivity */
947         if (!(Attributes & OBJ_CASE_INSENSITIVE))
948         {
949             /* Tell the driver about it */
950             FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
951         }
952 
953         /* Now set the file object */
954         Irp->Tail.Overlay.OriginalFileObject = FileObject;
955         StackLoc->FileObject = FileObject;
956 
957         /* Check if the file object has a name */
958         if (RemainingName->Length)
959         {
960             /* Setup the unicode string */
961             FileObject->FileName.MaximumLength = RemainingName->Length +
962                                                  sizeof(WCHAR);
963             FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
964                                                                 FileObject->
965                                                                 FileName.
966                                                                 MaximumLength,
967                                                                 TAG_IO_NAME);
968             if (!FileObject->FileName.Buffer)
969             {
970                 /* Failed to allocate the name, free the IRP */
971                 IoFreeIrp(Irp);
972 
973                 /* Dereference the device object and VPB */
974                 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
975                 if (Vpb) IopDereferenceVpbAndFree(Vpb);
976 
977                 /* Clear the FO and dereference it */
978                 FileObject->DeviceObject = NULL;
979                 if (!UseDummyFile) ObDereferenceObject(FileObject);
980 
981                 /* Fail */
982                 return STATUS_INSUFFICIENT_RESOURCES;
983             }
984         }
985 
986         /* Copy the name */
987         RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
988 
989         /* Initialize the File Object event and set the FO */
990         KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
991         OpenPacket->FileObject = FileObject;
992 
993         /* Queue the IRP and call the driver */
994         IopQueueIrpToThread(Irp);
995         Status = IoCallDriver(DeviceObject, Irp);
996         if (Status == STATUS_PENDING)
997         {
998             /* Wait for the driver to complete the create */
999             KeWaitForSingleObject(&FileObject->Event,
1000                                   Executive,
1001                                   KernelMode,
1002                                   FALSE,
1003                                   NULL);
1004 
1005             /* Get the new status */
1006             Status = IoStatusBlock.Status;
1007         }
1008         else
1009         {
1010             /* We'll have to complete it ourselves */
1011             ASSERT(!Irp->PendingReturned);
1012             ASSERT(!Irp->MdlAddress);
1013 
1014             /* Handle name change if required */
1015             if (Status == STATUS_REPARSE)
1016             {
1017                 /* Check this is a mount point */
1018                 if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
1019                 {
1020                     PREPARSE_DATA_BUFFER ReparseData;
1021 
1022                     /* Reparse point attributes were passed by the driver in the auxiliary buffer */
1023                     ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
1024                     ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
1025 
1026                     ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
1027                     ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1028                     ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1029 
1030                     IopDoNameTransmogrify(Irp, FileObject, ReparseData);
1031                 }
1032             }
1033 
1034             /* Completion happens at APC_LEVEL */
1035             KeRaiseIrql(APC_LEVEL, &OldIrql);
1036 
1037             /* Get the new I/O Status block ourselves */
1038             IoStatusBlock = Irp->IoStatus;
1039             Status = IoStatusBlock.Status;
1040 
1041             /* Manually signal the even, we can't have any waiters */
1042             FileObject->Event.Header.SignalState = 1;
1043 
1044             /* Now that we've signaled the events, de-associate the IRP */
1045             IopUnQueueIrpFromThread(Irp);
1046 
1047             /* Check if the IRP had an input buffer */
1048             if ((Irp->Flags & IRP_BUFFERED_IO) &&
1049                 (Irp->Flags & IRP_DEALLOCATE_BUFFER))
1050             {
1051                 /* Free it. A driver might've tacked one on */
1052                 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
1053             }
1054 
1055             /* Free the IRP and bring the IRQL back down */
1056             IoFreeIrp(Irp);
1057             KeLowerIrql(OldIrql);
1058         }
1059 
1060         /* Copy the I/O Status */
1061         OpenPacket->Information = IoStatusBlock.Information;
1062 
1063         /* The driver failed to create the file */
1064         if (!NT_SUCCESS(Status))
1065         {
1066             /* Check if we have a name */
1067             if (FileObject->FileName.Length)
1068             {
1069                 /* Free it */
1070                 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1071                 FileObject->FileName.Length = 0;
1072             }
1073 
1074             /* Clear its device object */
1075             FileObject->DeviceObject = NULL;
1076 
1077             /* Save this now because the FO might go away */
1078             OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
1079                             TRUE : FALSE;
1080 
1081             /* Clear the file object in the open packet */
1082             OpenPacket->FileObject = NULL;
1083 
1084             /* Dereference the file object */
1085             if (!UseDummyFile) ObDereferenceObject(FileObject);
1086 
1087             /* Dereference the device object */
1088             IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1089 
1090             /* Unless the driver cancelled the open, dereference the VPB */
1091             if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
1092 
1093             /* Set the status and return */
1094             OpenPacket->FinalStatus = Status;
1095             return Status;
1096         }
1097         else if (Status == STATUS_REPARSE)
1098         {
1099             if (OpenPacket->Information == IO_REPARSE ||
1100                 OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1101             {
1102                 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1103                 if (CompleteName->MaximumLength < FileObject->FileName.Length)
1104                 {
1105                     PWSTR NewCompleteName;
1106 
1107                     /* Allocate a new buffer for the string */
1108                     NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
1109                     if (NewCompleteName == NULL)
1110                     {
1111                         OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
1112                         return STATUS_INSUFFICIENT_RESOURCES;
1113                     }
1114 
1115                     /* Release the old one */
1116                     if (CompleteName->Buffer != NULL)
1117                     {
1118                         ExFreePoolWithTag(CompleteName->Buffer, 0);
1119                     }
1120 
1121                     /* And setup the new one */
1122                     CompleteName->Buffer = NewCompleteName;
1123                     CompleteName->MaximumLength = FileObject->FileName.Length;
1124                 }
1125 
1126                 /* Copy our new complete name */
1127                 RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
1128 
1129                 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1130                 {
1131                     OpenPacket->RelatedFileObject = NULL;
1132                 }
1133             }
1134 
1135             /* Check if we have a name */
1136             if (FileObject->FileName.Length)
1137             {
1138                 /* Free it */
1139                 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1140                 FileObject->FileName.Length = 0;
1141             }
1142 
1143             /* Clear its device object */
1144             FileObject->DeviceObject = NULL;
1145 
1146             /* Clear the file object in the open packet */
1147             OpenPacket->FileObject = NULL;
1148 
1149             /* Dereference the file object */
1150             if (!UseDummyFile) ObDereferenceObject(FileObject);
1151 
1152             /* Dereference the device object */
1153             IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1154 
1155             /* Unless the driver cancelled the open, dereference the VPB */
1156             if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
1157 
1158             if (OpenPacket->Information != IO_REMOUNT)
1159             {
1160                 OpenPacket->RelatedFileObject = NULL;
1161 
1162                 /* Inform we traversed a mount point for later attempt */
1163                 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1164                 {
1165                     OpenPacket->TraversedMountPoint = 1;
1166                 }
1167 
1168                 /* In case we override checks, but got this on volume open, fail hard */
1169                 if (OpenPacket->Override)
1170                 {
1171                     KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
1172                                  (ULONG_PTR)OriginalDeviceObject,
1173                                  (ULONG_PTR)DeviceObject,
1174                                  (ULONG_PTR)CompleteName,
1175                                  OpenPacket->Information);
1176                 }
1177 
1178                 /* Return to IO/OB so that information can be upgraded */
1179                 return STATUS_REPARSE;
1180             }
1181 
1182             /* Loop again and reattempt an opening */
1183             continue;
1184         }
1185 
1186         break;
1187     }
1188 
1189     if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
1190         return STATUS_UNSUCCESSFUL;
1191 
1192     /* Get the owner of the File Object */
1193     OwnerDevice = IoGetRelatedDeviceObject(FileObject);
1194 
1195     /*
1196      * It's possible that the device to whom we sent the IRP to
1197      * isn't actually the device that ended opening the file object
1198      * internally.
1199      */
1200     if (OwnerDevice != DeviceObject)
1201     {
1202         /* We have to de-reference the VPB we had associated */
1203         if (Vpb) IopDereferenceVpbAndFree(Vpb);
1204 
1205         /* And re-associate with the actual one */
1206         Vpb = FileObject->Vpb;
1207         if (Vpb) InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
1208     }
1209 
1210     /* Make sure we are not using a dummy */
1211     if (!UseDummyFile)
1212     {
1213         /* Check if this was a volume open */
1214         if ((!(FileObject->RelatedFileObject) ||
1215               (FileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN)) &&
1216             !(FileObject->FileName.Length))
1217         {
1218             /* All signs point to it, but make sure it was actually an FSD */
1219             if ((OwnerDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1220                 (OwnerDevice->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1221                 (OwnerDevice->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) ||
1222                 (OwnerDevice->DeviceType == FILE_DEVICE_FILE_SYSTEM))
1223             {
1224                 /* The owner device is an FSD, so this is a volume open for real */
1225                 FileObject->Flags |= FO_VOLUME_OPEN;
1226             }
1227         }
1228 
1229         /* Reference the object and set the parse check */
1230         ObReferenceObject(FileObject);
1231         *Object = FileObject;
1232         OpenPacket->FinalStatus = IoStatusBlock.Status;
1233         OpenPacket->ParseCheck = TRUE;
1234         return OpenPacket->FinalStatus;
1235     }
1236     else
1237     {
1238         /* Check if this was a query */
1239         if (OpenPacket->QueryOnly)
1240         {
1241             /* Check if the caller wants basic info only */
1242             if (!OpenPacket->FullAttributes)
1243             {
1244                 /* Allocate the buffer */
1245                 FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
1246                                                       sizeof(*FileBasicInfo),
1247                                                       TAG_IO);
1248                 if (FileBasicInfo)
1249                 {
1250                     /* Do the query */
1251                     Status = IoQueryFileInformation(FileObject,
1252                                                     FileBasicInformation,
1253                                                     sizeof(*FileBasicInfo),
1254                                                     FileBasicInfo,
1255                                                     &ReturnLength);
1256                     if (NT_SUCCESS(Status))
1257                     {
1258                         /* Copy the data */
1259                         RtlCopyMemory(OpenPacket->BasicInformation,
1260                                       FileBasicInfo,
1261                                       ReturnLength);
1262                     }
1263 
1264                     /* Free our buffer */
1265                     ExFreePoolWithTag(FileBasicInfo, TAG_IO);
1266                 }
1267                 else
1268                 {
1269                     /* Fail */
1270                     Status = STATUS_INSUFFICIENT_RESOURCES;
1271                 }
1272             }
1273             else
1274             {
1275                 /* This is a full query */
1276                 Status = IoQueryFileInformation(
1277                     FileObject,
1278                     FileNetworkOpenInformation,
1279                     sizeof(FILE_NETWORK_OPEN_INFORMATION),
1280                     OpenPacket->NetworkInformation,
1281                     &ReturnLength);
1282                 if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
1283             }
1284         }
1285 
1286         /* Delete the file object */
1287         IopDeleteFile(FileObject);
1288 
1289         /* Clear out the file */
1290         OpenPacket->FileObject = NULL;
1291 
1292         /* Set and return status */
1293         OpenPacket->FinalStatus = Status;
1294         OpenPacket->ParseCheck = TRUE;
1295         return Status;
1296     }
1297 }
1298 
1299 NTSTATUS
1300 NTAPI
1301 IopParseFile(IN PVOID ParseObject,
1302              IN PVOID ObjectType,
1303              IN OUT PACCESS_STATE AccessState,
1304              IN KPROCESSOR_MODE AccessMode,
1305              IN ULONG Attributes,
1306              IN OUT PUNICODE_STRING CompleteName,
1307              IN OUT PUNICODE_STRING RemainingName,
1308              IN OUT PVOID Context OPTIONAL,
1309              IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
1310              OUT PVOID *Object)
1311 {
1312     PVOID DeviceObject;
1313     POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
1314 
1315     /* Validate the open packet */
1316     if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
1317 
1318     /* Get the device object */
1319     DeviceObject = IoGetRelatedDeviceObject(ParseObject);
1320     OpenPacket->RelatedFileObject = ParseObject;
1321 
1322     /* Call the main routine */
1323     return IopParseDevice(DeviceObject,
1324                           ObjectType,
1325                           AccessState,
1326                           AccessMode,
1327                           Attributes,
1328                           CompleteName,
1329                           RemainingName,
1330                           OpenPacket,
1331                           SecurityQos,
1332                           Object);
1333 }
1334 
1335 VOID
1336 NTAPI
1337 IopDeleteFile(IN PVOID ObjectBody)
1338 {
1339     PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1340     PIRP Irp;
1341     PIO_STACK_LOCATION StackPtr;
1342     NTSTATUS Status;
1343     KEVENT Event;
1344     PDEVICE_OBJECT DeviceObject;
1345     BOOLEAN DereferenceDone = FALSE;
1346     PVPB Vpb;
1347     KIRQL OldIrql;
1348     IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1349 
1350     /* Check if the file has a device object */
1351     if (FileObject->DeviceObject)
1352     {
1353         /* Check if this is a direct open or not */
1354         if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1355         {
1356             /* Get the attached device */
1357             DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1358         }
1359         else
1360         {
1361             /* Use the file object's device object */
1362             DeviceObject = IoGetRelatedDeviceObject(FileObject);
1363         }
1364 
1365         /* Sanity check */
1366         ASSERT(!(FileObject->Flags & FO_SYNCHRONOUS_IO) ||
1367                (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE));
1368 
1369         /* Check if the handle wasn't created yet */
1370         if (!(FileObject->Flags & FO_HANDLE_CREATED))
1371         {
1372             /* Send the cleanup IRP */
1373             IopCloseFile(NULL, ObjectBody, 0, 1, 1);
1374         }
1375 
1376         /* Clear and set up Events */
1377         KeClearEvent(&FileObject->Event);
1378         KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1379 
1380         /* Allocate an IRP */
1381         Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
1382 
1383         /* Set it up */
1384         Irp->UserEvent = &Event;
1385         Irp->UserIosb = &Irp->IoStatus;
1386         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1387         Irp->Tail.Overlay.OriginalFileObject = FileObject;
1388         Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1389 
1390         /* Set up Stack Pointer Data */
1391         StackPtr = IoGetNextIrpStackLocation(Irp);
1392         StackPtr->MajorFunction = IRP_MJ_CLOSE;
1393         StackPtr->FileObject = FileObject;
1394 
1395         /* Queue the IRP */
1396         IopQueueIrpToThread(Irp);
1397 
1398         /* Get the VPB and check if this isn't a direct open */
1399         Vpb = FileObject->Vpb;
1400         if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1401         {
1402             /* Dereference the VPB before the close */
1403             InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
1404         }
1405 
1406         /* Check if the FS will never disappear by itself */
1407         if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
1408         {
1409             /* Dereference it */
1410             InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
1411             DereferenceDone = TRUE;
1412         }
1413 
1414         /* Call the FS Driver */
1415         Status = IoCallDriver(DeviceObject, Irp);
1416         if (Status == STATUS_PENDING)
1417         {
1418             /* Wait for completion */
1419             KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1420         }
1421 
1422         /* De-queue the IRP */
1423         KeRaiseIrql(APC_LEVEL, &OldIrql);
1424         IopUnQueueIrpFromThread(Irp);
1425         KeLowerIrql(OldIrql);
1426 
1427         /* Free the IRP */
1428         IoFreeIrp(Irp);
1429 
1430         /* Clear the file name */
1431         if (FileObject->FileName.Buffer)
1432         {
1433            ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1434            FileObject->FileName.Buffer = NULL;
1435         }
1436 
1437         /* Check if the FO had a completion port */
1438         if (FileObject->CompletionContext)
1439         {
1440             /* Free it */
1441             ObDereferenceObject(FileObject->CompletionContext->Port);
1442             ExFreePool(FileObject->CompletionContext);
1443         }
1444 
1445         /* Check if the FO had extension */
1446         if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1447         {
1448             /* Release filter context structure if any */
1449             FsRtlPTeardownPerFileObjectContexts(FileObject);
1450         }
1451 
1452         /* Check if dereference has been done yet */
1453         if (!DereferenceDone)
1454         {
1455             /* Dereference device object */
1456             IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
1457         }
1458     }
1459 }
1460 
1461 PDEVICE_OBJECT
1462 NTAPI
1463 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
1464 {
1465     PDEVICE_OBJECT PDO = DeviceObject;
1466 
1467     /* Go down the stack to attempt to get the PDO */
1468     for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
1469            PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
1470 
1471     return PDO;
1472 }
1473 
1474 PDEVICE_OBJECT
1475 NTAPI
1476 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
1477 {
1478     KIRQL OldIrql;
1479     PDEVICE_OBJECT PDO;
1480 
1481     ASSERT(DeviceObject != NULL);
1482 
1483     OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1484     /* Get the base DO */
1485     PDO = IopGetDeviceAttachmentBase(DeviceObject);
1486     /* Check whether that's really a PDO and if so, keep it */
1487     if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
1488     {
1489         PDO = NULL;
1490     }
1491     else
1492     {
1493         ObReferenceObject(PDO);
1494     }
1495     KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1496 
1497     return PDO;
1498 }
1499 
1500 NTSTATUS
1501 NTAPI
1502 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
1503                                IN PSECURITY_INFORMATION SecurityInformation,
1504                                IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1505                                IN POOL_TYPE PoolType,
1506                                IN PGENERIC_MAPPING GenericMapping)
1507 {
1508     NTSTATUS Status;
1509     PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
1510 
1511     PAGED_CODE();
1512 
1513     /* Keep attempting till we find our old SD or fail */
1514     while (TRUE)
1515     {
1516         KeEnterCriticalRegion();
1517         ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
1518 
1519         /* Get our old SD and reference it */
1520         OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
1521         if (OldSecurityDescriptor != NULL)
1522         {
1523             ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1524         }
1525 
1526         ExReleaseResourceLite(&IopSecurityResource);
1527         KeLeaveCriticalRegion();
1528 
1529         /* Set the SD information */
1530         NewSecurityDescriptor = OldSecurityDescriptor;
1531         Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
1532                                              SecurityDescriptor, &NewSecurityDescriptor,
1533                                              PoolType, GenericMapping);
1534 
1535         if (!NT_SUCCESS(Status))
1536         {
1537             if (OldSecurityDescriptor != NULL)
1538             {
1539                 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1540             }
1541 
1542             break;
1543         }
1544 
1545         /* Add the new DS to the internal cache */
1546         Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
1547                                          &CachedSecurityDescriptor, 1);
1548         ExFreePool(NewSecurityDescriptor);
1549         if (!NT_SUCCESS(Status))
1550         {
1551             ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1552             break;
1553         }
1554 
1555         KeEnterCriticalRegion();
1556         ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1557         /* Check if someone changed it in our back */
1558         if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
1559         {
1560             /* We're clear, do the swap */
1561             DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1562             ExReleaseResourceLite(&IopSecurityResource);
1563             KeLeaveCriticalRegion();
1564 
1565             /* And dereference old SD (twice - us + not in use) */
1566             ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
1567 
1568             break;
1569         }
1570         ExReleaseResourceLite(&IopSecurityResource);
1571         KeLeaveCriticalRegion();
1572 
1573         /* If so, try again */
1574         ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1575         ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
1576     }
1577 
1578     return Status;
1579 }
1580 
1581 NTSTATUS
1582 NTAPI
1583 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
1584                                 IN PDEVICE_OBJECT PhysicalDeviceObject,
1585                                 IN PSECURITY_INFORMATION SecurityInformation,
1586                                 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1587                                 IN POOL_TYPE PoolType,
1588                                 IN PGENERIC_MAPPING GenericMapping)
1589 {
1590     PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
1591     NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
1592 
1593     PAGED_CODE();
1594 
1595     ASSERT(PhysicalDeviceObject != NULL);
1596 
1597     /* We always reference the DO we're working on */
1598     ObReferenceObject(CurrentDO);
1599 
1600     /* Go up from PDO to latest DO */
1601     do
1602     {
1603         /* Attempt to set the new SD on it */
1604         TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
1605                                                    SecurityDescriptor, PoolType,
1606                                                    GenericMapping);
1607         /* Was our last one? Remember that status then */
1608         if (CurrentDO == UpperDeviceObject)
1609         {
1610             Status = TmpStatus;
1611         }
1612 
1613         /* Try to move to the next DO (and thus, reference it) */
1614         NextDevice = CurrentDO->AttachedDevice;
1615         if (NextDevice)
1616         {
1617             ObReferenceObject(NextDevice);
1618         }
1619 
1620         /* Dereference current DO and move to the next one */
1621         ObDereferenceObject(CurrentDO);
1622         CurrentDO = NextDevice;
1623     }
1624     while (CurrentDO != NULL);
1625 
1626     return Status;
1627 }
1628 
1629 NTSTATUS
1630 NTAPI
1631 IopGetSetSecurityObject(IN PVOID ObjectBody,
1632                         IN SECURITY_OPERATION_CODE OperationCode,
1633                         IN PSECURITY_INFORMATION SecurityInformation,
1634                         IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1635                         IN OUT PULONG BufferLength,
1636                         IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
1637                         IN POOL_TYPE PoolType,
1638                         IN OUT PGENERIC_MAPPING GenericMapping)
1639 {
1640     IO_STATUS_BLOCK IoStatusBlock;
1641     PIO_STACK_LOCATION StackPtr;
1642     PFILE_OBJECT FileObject;
1643     PDEVICE_OBJECT DeviceObject;
1644     PIRP Irp;
1645     BOOLEAN LocalEvent = FALSE;
1646     KEVENT Event;
1647     NTSTATUS Status = STATUS_SUCCESS;
1648     PAGED_CODE();
1649     IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1650 
1651     /* Check if this is a device or file */
1652     if (((PFILE_OBJECT)ObjectBody)->Type == IO_TYPE_DEVICE)
1653     {
1654         /* It's a device */
1655         DeviceObject = (PDEVICE_OBJECT)ObjectBody;
1656         FileObject = NULL;
1657     }
1658     else
1659     {
1660         /* It's a file */
1661         FileObject = (PFILE_OBJECT)ObjectBody;
1662 
1663         /* Check if this is a direct open */
1664         if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1665         {
1666             /* Get the Device Object */
1667             DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1668         }
1669         else
1670         {
1671             /* Otherwise, use the direct device*/
1672             DeviceObject = FileObject->DeviceObject;
1673         }
1674     }
1675 
1676     /* Check if the request was for a device object */
1677     if (!(FileObject) ||
1678         (!(FileObject->FileName.Length) && !(FileObject->RelatedFileObject)) ||
1679         (FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1680     {
1681         /* Check what kind of request this was */
1682         if (OperationCode == QuerySecurityDescriptor)
1683         {
1684             return SeQuerySecurityDescriptorInfo(SecurityInformation,
1685                                                  SecurityDescriptor,
1686                                                  BufferLength,
1687                                                  &DeviceObject->SecurityDescriptor);
1688         }
1689         else if (OperationCode == DeleteSecurityDescriptor)
1690         {
1691             /* Simply return success */
1692             return STATUS_SUCCESS;
1693         }
1694         else if (OperationCode == AssignSecurityDescriptor)
1695         {
1696             Status = STATUS_SUCCESS;
1697 
1698             /* Make absolutely sure this is a device object */
1699             if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
1700             {
1701                 PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
1702 
1703                 /* Add the security descriptor in cache */
1704                 Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
1705                 if (NT_SUCCESS(Status))
1706                 {
1707                     KeEnterCriticalRegion();
1708                     ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1709 
1710                     /* Assign the Security Descriptor */
1711                     DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1712 
1713                     ExReleaseResourceLite(&IopSecurityResource);
1714                     KeLeaveCriticalRegion();
1715                 }
1716             }
1717 
1718             /* Return status */
1719             return Status;
1720         }
1721         else if (OperationCode == SetSecurityDescriptor)
1722         {
1723             /* Get the Physical Device Object if any */
1724             PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
1725 
1726             if (PDO != NULL)
1727             {
1728                 /* Apply the new SD to any DO in the path from PDO to current DO */
1729                 Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
1730                                                          SecurityInformation,
1731                                                          SecurityDescriptor,
1732                                                          PoolType, GenericMapping);
1733                 ObDereferenceObject(PDO);
1734             }
1735             else
1736             {
1737                 /* Otherwise, just set for ourselves */
1738                 Status = IopSetDeviceSecurityDescriptor(DeviceObject,
1739                                                         SecurityInformation,
1740                                                         SecurityDescriptor,
1741                                                         PoolType, GenericMapping);
1742             }
1743 
1744             return STATUS_SUCCESS;
1745         }
1746 
1747         /* Shouldn't happen */
1748         return STATUS_SUCCESS;
1749     }
1750     else if (OperationCode == DeleteSecurityDescriptor)
1751     {
1752         /* Same as for devices, do nothing */
1753         return STATUS_SUCCESS;
1754     }
1755 
1756     /* At this point, we know we're a file. Reference it */
1757     ObReferenceObject(FileObject);
1758 
1759     /* Check if we should use Sync IO or not */
1760     if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1761     {
1762         /* Lock the file object */
1763         Status = IopLockFileObject(FileObject, ExGetPreviousMode());
1764         if (Status != STATUS_SUCCESS)
1765         {
1766             ObDereferenceObject(FileObject);
1767             return Status;
1768         }
1769     }
1770     else
1771     {
1772         /* Use local event */
1773         KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1774         LocalEvent = TRUE;
1775     }
1776 
1777     /* Clear the File Object event */
1778     KeClearEvent(&FileObject->Event);
1779 
1780     /* Get the device object */
1781     DeviceObject = IoGetRelatedDeviceObject(FileObject);
1782 
1783     /* Allocate the IRP */
1784     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1785     if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1786 
1787     /* Set the IRP */
1788     Irp->Tail.Overlay.OriginalFileObject = FileObject;
1789     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1790     Irp->RequestorMode = ExGetPreviousMode();
1791     Irp->UserIosb = &IoStatusBlock;
1792     Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1793     Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1794     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1795 
1796     /* Set Stack Parameters */
1797     StackPtr = IoGetNextIrpStackLocation(Irp);
1798     StackPtr->FileObject = FileObject;
1799 
1800     /* Check if this is a query or set */
1801     if (OperationCode == QuerySecurityDescriptor)
1802     {
1803         /* Set the major function and parameters */
1804         StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
1805         StackPtr->Parameters.QuerySecurity.SecurityInformation =
1806             *SecurityInformation;
1807         StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
1808         Irp->UserBuffer = SecurityDescriptor;
1809     }
1810     else
1811     {
1812         /* Set the major function and parameters for a set */
1813         StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
1814         StackPtr->Parameters.SetSecurity.SecurityInformation =
1815             *SecurityInformation;
1816         StackPtr->Parameters.SetSecurity.SecurityDescriptor =
1817             SecurityDescriptor;
1818     }
1819 
1820     /* Queue the IRP */
1821     IopQueueIrpToThread(Irp);
1822 
1823     /* Update operation counts */
1824     IopUpdateOperationCount(IopOtherTransfer);
1825 
1826     /* Call the Driver */
1827     Status = IoCallDriver(DeviceObject, Irp);
1828 
1829     /* Check if this was async I/O */
1830     if (LocalEvent)
1831     {
1832         /* Check if the IRP is pending completion */
1833         if (Status == STATUS_PENDING)
1834         {
1835             /* Wait on the local event */
1836             KeWaitForSingleObject(&Event,
1837                                   Executive,
1838                                   KernelMode,
1839                                   FALSE,
1840                                   NULL);
1841             Status = IoStatusBlock.Status;
1842         }
1843     }
1844     else
1845     {
1846         /* Check if the IRP is pending completion */
1847         if (Status == STATUS_PENDING)
1848         {
1849             /* Wait on the file object */
1850             KeWaitForSingleObject(&FileObject->Event,
1851                                   Executive,
1852                                   KernelMode,
1853                                   FALSE,
1854                                   NULL);
1855             Status = FileObject->FinalStatus;
1856         }
1857 
1858         /* Release the lock */
1859         IopUnlockFileObject(FileObject);
1860     }
1861 
1862     /* This Driver doesn't implement Security, so try to give it a default */
1863     if (Status == STATUS_INVALID_DEVICE_REQUEST)
1864     {
1865         /* Was this a query? */
1866         if (OperationCode == QuerySecurityDescriptor)
1867         {
1868             /* Set a World Security Descriptor */
1869             Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
1870                                                   SecurityDescriptor,
1871                                                   BufferLength);
1872         }
1873         else
1874         {
1875             /* It wasn't a query, so just fake success */
1876             Status = STATUS_SUCCESS;
1877         }
1878     }
1879     else if (OperationCode == QuerySecurityDescriptor)
1880     {
1881         /* Callers usually expect the normalized form */
1882         if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_BUFFER_TOO_SMALL;
1883 
1884         _SEH2_TRY
1885         {
1886             /* Return length */
1887             *BufferLength = (ULONG)IoStatusBlock.Information;
1888         }
1889         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1890         {
1891             /* Get the exception code */
1892             Status = _SEH2_GetExceptionCode();
1893         }
1894         _SEH2_END;
1895     }
1896 
1897     /* Return Status */
1898     return Status;
1899 }
1900 
1901 NTSTATUS
1902 NTAPI
1903 IopQueryName(IN PVOID ObjectBody,
1904              IN BOOLEAN HasName,
1905              OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1906              IN ULONG Length,
1907              OUT PULONG ReturnLength,
1908              IN KPROCESSOR_MODE PreviousMode)
1909 {
1910     return IopQueryNameInternal(ObjectBody,
1911                                 HasName,
1912                                 FALSE,
1913                                 ObjectNameInfo,
1914                                 Length,
1915                                 ReturnLength,
1916                                 PreviousMode);
1917 }
1918 
1919 NTSTATUS
1920 NTAPI
1921 IopQueryNameInternal(IN PVOID ObjectBody,
1922                      IN BOOLEAN HasName,
1923                      IN BOOLEAN QueryDosName,
1924                      OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1925                      IN ULONG Length,
1926                      OUT PULONG ReturnLength,
1927                      IN KPROCESSOR_MODE PreviousMode)
1928 {
1929     POBJECT_NAME_INFORMATION LocalInfo;
1930     PFILE_NAME_INFORMATION LocalFileInfo;
1931     PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1932     ULONG LocalReturnLength, FileLength;
1933     BOOLEAN LengthMismatch = FALSE;
1934     NTSTATUS Status;
1935     PWCHAR p;
1936     PDEVICE_OBJECT DeviceObject;
1937     BOOLEAN NoObCall;
1938 
1939     IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1940 
1941     /* Validate length */
1942     if (Length < sizeof(OBJECT_NAME_INFORMATION))
1943     {
1944         /* Wrong length, fail */
1945         *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1946         return STATUS_INFO_LENGTH_MISMATCH;
1947     }
1948 
1949     /* Allocate Buffer */
1950     LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1951     if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1952 
1953     /* Query DOS name if the caller asked to */
1954     NoObCall = FALSE;
1955     if (QueryDosName)
1956     {
1957         DeviceObject = FileObject->DeviceObject;
1958 
1959         /* In case of a network file system, don't call mountmgr */
1960         if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
1961         {
1962             /* We'll store separator and terminator */
1963             LocalReturnLength = sizeof(OBJECT_NAME_INFORMATION) + 2 * sizeof(WCHAR);
1964             if (Length < LocalReturnLength)
1965             {
1966                 Status = STATUS_BUFFER_OVERFLOW;
1967             }
1968             else
1969             {
1970                 LocalInfo->Name.Length = sizeof(WCHAR);
1971                 LocalInfo->Name.MaximumLength = sizeof(WCHAR);
1972                 LocalInfo->Name.Buffer = (PVOID)((ULONG_PTR)LocalInfo + sizeof(OBJECT_NAME_INFORMATION));
1973                 LocalInfo->Name.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
1974                 Status = STATUS_SUCCESS;
1975             }
1976         }
1977         /* Otherwise, call mountmgr to get DOS name */
1978         else
1979         {
1980             Status = IoVolumeDeviceToDosName(DeviceObject, &LocalInfo->Name);
1981             LocalReturnLength = LocalInfo->Name.Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
1982         }
1983     }
1984 
1985     /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
1986     if (!QueryDosName || !NT_SUCCESS(Status))
1987     {
1988         /* Query the name */
1989         Status = ObQueryNameString(FileObject->DeviceObject,
1990                                    LocalInfo,
1991                                    Length,
1992                                    &LocalReturnLength);
1993     }
1994     else
1995     {
1996         NoObCall = TRUE;
1997     }
1998 
1999     if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
2000     {
2001         /* Free the buffer and fail */
2002         ExFreePoolWithTag(LocalInfo, TAG_IO);
2003         return Status;
2004     }
2005 
2006     /* Get buffer pointer */
2007     p = (PWCHAR)(ObjectNameInfo + 1);
2008 
2009     _SEH2_TRY
2010     {
2011         /* Copy the information */
2012         if (QueryDosName && NoObCall)
2013         {
2014             ASSERT(PreviousMode == KernelMode);
2015 
2016             /* Copy structure first */
2017             RtlCopyMemory(ObjectNameInfo,
2018                           LocalInfo,
2019                           (Length >= LocalReturnLength ? sizeof(OBJECT_NAME_INFORMATION) : Length));
2020             /* Name then */
2021             RtlCopyMemory(p, LocalInfo->Name.Buffer,
2022                           (Length >= LocalReturnLength ? LocalInfo->Name.Length : Length - sizeof(OBJECT_NAME_INFORMATION)));
2023 
2024             if (FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)
2025             {
2026                 ExFreePool(LocalInfo->Name.Buffer);
2027             }
2028         }
2029         else
2030         {
2031             RtlCopyMemory(ObjectNameInfo,
2032                           LocalInfo,
2033                           (LocalReturnLength > Length) ?
2034                           Length : LocalReturnLength);
2035         }
2036 
2037         /* Set buffer pointer */
2038         ObjectNameInfo->Name.Buffer = p;
2039 
2040         /* Advance in buffer */
2041         p += (LocalInfo->Name.Length / sizeof(WCHAR));
2042 
2043         /* Check if this already filled our buffer */
2044         if (LocalReturnLength > Length)
2045         {
2046             /* Set the length mismatch to true, so that we can return
2047              * the proper buffer size to the caller later
2048              */
2049             LengthMismatch = TRUE;
2050 
2051             /* Save the initial buffer length value */
2052             *ReturnLength = LocalReturnLength;
2053         }
2054 
2055         /* Now get the file name buffer and check the length needed */
2056         LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
2057         FileLength = Length -
2058                      LocalReturnLength +
2059                      FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2060 
2061         /* Query the File name */
2062         if (PreviousMode == KernelMode &&
2063             BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2064         {
2065             Status = IopGetFileInformation(FileObject,
2066                                            LengthMismatch ? Length : FileLength,
2067                                            FileNameInformation,
2068                                            LocalFileInfo,
2069                                            &LocalReturnLength);
2070         }
2071         else
2072         {
2073             Status = IoQueryFileInformation(FileObject,
2074                                             FileNameInformation,
2075                                             LengthMismatch ? Length : FileLength,
2076                                             LocalFileInfo,
2077                                             &LocalReturnLength);
2078         }
2079         if (NT_ERROR(Status))
2080         {
2081             /* Allow status that would mean it's not implemented in the storage stack */
2082             if (Status != STATUS_INVALID_PARAMETER && Status != STATUS_INVALID_DEVICE_REQUEST &&
2083                 Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_INFO_CLASS)
2084             {
2085                 _SEH2_LEAVE;
2086             }
2087 
2088             /* In such case, zero output */
2089             LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2090             LocalFileInfo->FileNameLength = 0;
2091             LocalFileInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
2092         }
2093         else
2094         {
2095             /* We'll at least return the name length */
2096             if (LocalReturnLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
2097             {
2098                 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2099             }
2100         }
2101 
2102         /* If the provided buffer is too small, return the required size */
2103         if (LengthMismatch)
2104         {
2105             /* Add the required length */
2106             *ReturnLength += LocalFileInfo->FileNameLength;
2107 
2108             /* Free the allocated buffer and return failure */
2109             Status = STATUS_BUFFER_OVERFLOW;
2110             _SEH2_LEAVE;
2111         }
2112 
2113         /* Now calculate the new lengths left */
2114         FileLength = LocalReturnLength -
2115                      FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2116         LocalReturnLength = (ULONG)((ULONG_PTR)p -
2117                                     (ULONG_PTR)ObjectNameInfo +
2118                                     LocalFileInfo->FileNameLength);
2119 
2120         /* Don't copy the name if it's not valid */
2121         if (LocalFileInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR)
2122         {
2123             /* Free the allocated buffer and return failure */
2124             Status = STATUS_OBJECT_PATH_INVALID;
2125             _SEH2_LEAVE;
2126         }
2127 
2128         /* Write the Name and null-terminate it */
2129         RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
2130         p += (FileLength / sizeof(WCHAR));
2131         *p = UNICODE_NULL;
2132         LocalReturnLength += sizeof(UNICODE_NULL);
2133 
2134         /* Return the length needed */
2135         *ReturnLength = LocalReturnLength;
2136 
2137         /* Setup the length and maximum length */
2138         FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
2139         ObjectNameInfo->Name.Length = (USHORT)FileLength -
2140                                               sizeof(OBJECT_NAME_INFORMATION);
2141         ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
2142                                                      sizeof(UNICODE_NULL);
2143     }
2144     _SEH2_FINALLY
2145     {
2146         /* Free buffer and return */
2147         ExFreePoolWithTag(LocalInfo, TAG_IO);
2148     } _SEH2_END;
2149 
2150     return Status;
2151 }
2152 
2153 VOID
2154 NTAPI
2155 IopCloseFile(IN PEPROCESS Process OPTIONAL,
2156              IN PVOID ObjectBody,
2157              IN ACCESS_MASK GrantedAccess,
2158              IN ULONG HandleCount,
2159              IN ULONG SystemHandleCount)
2160 {
2161     PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
2162     KEVENT Event;
2163     PIRP Irp;
2164     PIO_STACK_LOCATION StackPtr;
2165     NTSTATUS Status;
2166     PDEVICE_OBJECT DeviceObject;
2167     KIRQL OldIrql;
2168     IO_STATUS_BLOCK IoStatusBlock;
2169     IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
2170 
2171     /* If this isn't the last handle for the current process, quit */
2172     if (HandleCount != 1) return;
2173 
2174     /* Check if the file is locked and has more then one handle opened */
2175     if ((FileObject->LockOperation) && (SystemHandleCount != 1))
2176     {
2177         /* Check if this is a direct open or not */
2178         if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
2179         {
2180             /* Get the attached device */
2181             DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2182         }
2183         else
2184         {
2185             /* Get the FO's device */
2186             DeviceObject = IoGetRelatedDeviceObject(FileObject);
2187         }
2188 
2189         /* Check if this is a sync FO and lock it */
2190         if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2191         {
2192             (VOID)IopLockFileObject(FileObject, KernelMode);
2193         }
2194 
2195         /* Go the FastIO path if possible, otherwise fall back to IRP */
2196         if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
2197             DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
2198             !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
2199         {
2200             /* Clear and set up Events */
2201             KeClearEvent(&FileObject->Event);
2202             KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2203 
2204             /* Allocate an IRP */
2205             Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2206 
2207             /* Set it up */
2208             Irp->UserEvent = &Event;
2209             Irp->UserIosb = &Irp->IoStatus;
2210             Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2211             Irp->Tail.Overlay.OriginalFileObject = FileObject;
2212             Irp->RequestorMode = KernelMode;
2213             Irp->Flags = IRP_SYNCHRONOUS_API;
2214             Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2215             ObReferenceObject(FileObject);
2216 
2217             /* Set up Stack Pointer Data */
2218             StackPtr = IoGetNextIrpStackLocation(Irp);
2219             StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2220             StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
2221             StackPtr->FileObject = FileObject;
2222 
2223             /* Queue the IRP */
2224             IopQueueIrpToThread(Irp);
2225 
2226             /* Call the FS Driver */
2227             Status = IoCallDriver(DeviceObject, Irp);
2228             if (Status == STATUS_PENDING)
2229             {
2230                 /* Wait for completion */
2231                 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2232             }
2233 
2234             /* IO will unqueue & free for us */
2235         }
2236 
2237         /* Release the lock if we were holding it */
2238         if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2239         {
2240             IopUnlockFileObject(FileObject);
2241         }
2242     }
2243 
2244     /* Make sure this is the last handle */
2245     if (SystemHandleCount != 1) return;
2246 
2247     /* Check if this is a direct open or not */
2248     if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2249     {
2250         /* Get the attached device */
2251         DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2252     }
2253     else
2254     {
2255         /* Get the FO's device */
2256         DeviceObject = IoGetRelatedDeviceObject(FileObject);
2257     }
2258 
2259     /* Set the handle created flag */
2260     FileObject->Flags |= FO_HANDLE_CREATED;
2261 
2262     /* Check if this is a sync FO and lock it */
2263     if (Process != NULL &&
2264         BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2265     {
2266         (VOID)IopLockFileObject(FileObject, KernelMode);
2267     }
2268 
2269     /* Clear and set up Events */
2270     KeClearEvent(&FileObject->Event);
2271     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2272 
2273     /* Allocate an IRP */
2274     Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2275 
2276     /* Set it up */
2277     Irp->UserEvent = &Event;
2278     Irp->UserIosb = &Irp->IoStatus;
2279     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2280     Irp->Tail.Overlay.OriginalFileObject = FileObject;
2281     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2282     Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2283 
2284     /* Set up Stack Pointer Data */
2285     StackPtr = IoGetNextIrpStackLocation(Irp);
2286     StackPtr->MajorFunction = IRP_MJ_CLEANUP;
2287     StackPtr->FileObject = FileObject;
2288 
2289     /* Queue the IRP */
2290     IopQueueIrpToThread(Irp);
2291 
2292     /* Update operation counts */
2293     IopUpdateOperationCount(IopOtherTransfer);
2294 
2295     /* Call the FS Driver */
2296     Status = IoCallDriver(DeviceObject, Irp);
2297     if (Status == STATUS_PENDING)
2298     {
2299         /* Wait for completion */
2300         KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2301     }
2302 
2303     /* Unqueue the IRP */
2304     KeRaiseIrql(APC_LEVEL, &OldIrql);
2305     IopUnQueueIrpFromThread(Irp);
2306     KeLowerIrql(OldIrql);
2307 
2308     /* Free the IRP */
2309     IoFreeIrp(Irp);
2310 
2311     /* Release the lock if we were holding it */
2312     if (Process != NULL &&
2313         BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2314     {
2315         IopUnlockFileObject(FileObject);
2316     }
2317 }
2318 
2319 NTSTATUS
2320 NTAPI
2321 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2322                        IN FILE_INFORMATION_CLASS FileInformationClass,
2323                        IN ULONG FileInformationSize,
2324                        OUT PVOID FileInformation)
2325 {
2326     NTSTATUS Status;
2327     KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
2328     DUMMY_FILE_OBJECT LocalFileObject;
2329     FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
2330     HANDLE Handle;
2331     OPEN_PACKET OpenPacket;
2332     BOOLEAN IsBasic;
2333     PAGED_CODE();
2334     IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
2335 
2336     /* Check if the caller was user mode */
2337     if (AccessMode != KernelMode)
2338     {
2339         /* Protect probe in SEH */
2340         _SEH2_TRY
2341         {
2342             /* Probe the buffer */
2343             ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
2344         }
2345         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2346         {
2347             /* Return the exception code */
2348             _SEH2_YIELD(return _SEH2_GetExceptionCode());
2349         }
2350         _SEH2_END;
2351     }
2352 
2353     /* Check if this is a basic or full request */
2354     IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
2355 
2356     /* Setup the Open Packet */
2357     RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2358     OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2359     OpenPacket.Size = sizeof(OPEN_PACKET);
2360     OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
2361     OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2362     OpenPacket.Disposition = FILE_OPEN;
2363     OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
2364     OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
2365                                     (AccessMode != KernelMode) ?
2366                                     &NetworkOpenInfo : FileInformation;
2367     OpenPacket.QueryOnly = TRUE;
2368     OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
2369     OpenPacket.LocalFileObject = &LocalFileObject;
2370 
2371     /* Update the operation count */
2372     IopUpdateOperationCount(IopOtherTransfer);
2373 
2374     /*
2375      * Attempt opening the file. This will call the I/O Parse Routine for
2376      * the File Object (IopParseDevice) which will use the dummy file obejct
2377      * send the IRP to its device object. Note that we have two statuses
2378      * to worry about: the Object Manager's status (in Status) and the I/O
2379      * status, which is in the Open Packet's Final Status, and determined
2380      * by the Parse Check member.
2381      */
2382     Status = ObOpenObjectByName(ObjectAttributes,
2383                                 NULL,
2384                                 AccessMode,
2385                                 NULL,
2386                                 FILE_READ_ATTRIBUTES,
2387                                 &OpenPacket,
2388                                 &Handle);
2389     if (OpenPacket.ParseCheck == FALSE)
2390     {
2391         /* Parse failed */
2392         DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2393                ObjectAttributes->ObjectName, Status);
2394         return Status;
2395     }
2396     else
2397     {
2398         /* Use the Io status */
2399         Status = OpenPacket.FinalStatus;
2400     }
2401 
2402     /* Check if we were succesful and this was user mode and a full query */
2403     if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
2404     {
2405         /* Enter SEH for copy */
2406         _SEH2_TRY
2407         {
2408             /* Copy the buffer back */
2409             RtlCopyMemory(FileInformation,
2410                           &NetworkOpenInfo,
2411                           FileInformationSize);
2412         }
2413         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2414         {
2415             /* Get exception code */
2416             Status = _SEH2_GetExceptionCode();
2417         }
2418         _SEH2_END;
2419     }
2420 
2421     /* Return status */
2422     return Status;
2423 }
2424 
2425 NTSTATUS
2426 NTAPI
2427 IopAcquireFileObjectLock(
2428     _In_ PFILE_OBJECT FileObject,
2429     _In_ KPROCESSOR_MODE WaitMode,
2430     _In_ BOOLEAN Alertable,
2431     _Out_ PBOOLEAN LockFailed)
2432 {
2433     NTSTATUS Status;
2434 
2435     PAGED_CODE();
2436 
2437     InterlockedIncrement((PLONG)&FileObject->Waiters);
2438 
2439     Status = STATUS_SUCCESS;
2440     do
2441     {
2442         if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
2443         {
2444             break;
2445         }
2446         Status = KeWaitForSingleObject(&FileObject->Lock,
2447                                        Executive,
2448                                        WaitMode,
2449                                        Alertable,
2450                                        NULL);
2451     } while (Status == STATUS_SUCCESS);
2452 
2453     InterlockedDecrement((PLONG)&FileObject->Waiters);
2454     if (Status == STATUS_SUCCESS)
2455     {
2456         ObReferenceObject(FileObject);
2457         *LockFailed = FALSE;
2458     }
2459     else
2460     {
2461         if (!FileObject->Busy && FileObject->Waiters)
2462         {
2463             KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2464         }
2465         *LockFailed = TRUE;
2466     }
2467 
2468     return Status;
2469 }
2470 
2471 PVOID
2472 NTAPI
2473 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
2474 {
2475     if (BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2476     {
2477         PFILE_OBJECT_EXTENSION FileObjectExtension;
2478 
2479         FileObjectExtension = FileObject->FileObjectExtension;
2480         return FileObjectExtension->FilterContext;
2481     }
2482 
2483     return NULL;
2484 }
2485 
2486 NTSTATUS
2487 NTAPI
2488 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
2489                                 IN PVOID FilterContext,
2490                                 IN BOOLEAN Define)
2491 {
2492     ULONG_PTR Success;
2493     PFILE_OBJECT_EXTENSION FileObjectExtension;
2494 
2495     if (!BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2496     {
2497         return STATUS_INVALID_PARAMETER;
2498     }
2499 
2500     FileObjectExtension = FileObject->FileObjectExtension;
2501     if (Define)
2502     {
2503         /* If define, just set the new value if not value is set
2504          * Success will only contain old value. It is valid if it is NULL
2505          */
2506         Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, FilterContext, NULL);
2507     }
2508     else
2509     {
2510         /* If not define, we want to reset filter context.
2511          * We will remove value (provided by the caller) and set NULL instead.
2512          * This will only success if caller provides correct previous value.
2513          * To catch whether it worked, we substract previous value to expect value:
2514          * If it matches (and thus, we reset), Success will contain 0
2515          * Otherwise, it will contain a non-zero value.
2516          */
2517         Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, NULL, FilterContext) - (ULONG_PTR)FilterContext;
2518     }
2519 
2520     /* If success isn't 0, it means we failed somewhere (set or unset) */
2521     if (Success != 0)
2522     {
2523         return STATUS_ALREADY_COMMITTED;
2524     }
2525 
2526     return STATUS_SUCCESS;
2527 }
2528 
2529 NTSTATUS
2530 NTAPI
2531 IopCreateFile(OUT PHANDLE FileHandle,
2532               IN ACCESS_MASK DesiredAccess,
2533               IN POBJECT_ATTRIBUTES ObjectAttributes,
2534               OUT PIO_STATUS_BLOCK IoStatusBlock,
2535               IN PLARGE_INTEGER AllocationSize OPTIONAL,
2536               IN ULONG FileAttributes,
2537               IN ULONG ShareAccess,
2538               IN ULONG Disposition,
2539               IN ULONG CreateOptions,
2540               IN PVOID EaBuffer OPTIONAL,
2541               IN ULONG EaLength,
2542               IN CREATE_FILE_TYPE CreateFileType,
2543               IN PVOID ExtraCreateParameters OPTIONAL,
2544               IN ULONG Options,
2545               IN ULONG Flags,
2546               IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2547 {
2548     KPROCESSOR_MODE AccessMode;
2549     HANDLE LocalHandle = 0;
2550     LARGE_INTEGER SafeAllocationSize;
2551     NTSTATUS Status = STATUS_SUCCESS;
2552     PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
2553     POPEN_PACKET OpenPacket;
2554     ULONG EaErrorOffset;
2555     PAGED_CODE();
2556 
2557     IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2558 
2559 
2560     /* Check if we have no parameter checking to do */
2561     if (Options & IO_NO_PARAMETER_CHECKING)
2562     {
2563         /* Then force kernel-mode access to avoid checks */
2564         AccessMode = KernelMode;
2565     }
2566     else
2567     {
2568         /* Otherwise, use the actual mode */
2569         AccessMode = ExGetPreviousMode();
2570     }
2571 
2572     /* Check if we need to do parameter checking */
2573     if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
2574     {
2575         /* Validate parameters */
2576         if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
2577         {
2578             DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2579             return STATUS_INVALID_PARAMETER;
2580         }
2581 
2582         if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
2583         {
2584             DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2585             return STATUS_INVALID_PARAMETER;
2586         }
2587 
2588         if (Disposition > FILE_MAXIMUM_DISPOSITION)
2589         {
2590             DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2591             return STATUS_INVALID_PARAMETER;
2592         }
2593 
2594         if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
2595         {
2596             DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2597             return STATUS_INVALID_PARAMETER;
2598         }
2599 
2600         if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
2601             (!(DesiredAccess & SYNCHRONIZE)))
2602         {
2603             DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2604             return STATUS_INVALID_PARAMETER;
2605         }
2606 
2607         if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
2608         {
2609             DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2610             return STATUS_INVALID_PARAMETER;
2611         }
2612 
2613         if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
2614             (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
2615         {
2616             DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2617             return STATUS_INVALID_PARAMETER;
2618         }
2619 
2620         if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2621             (CreateOptions & ~(FILE_DIRECTORY_FILE |
2622                                FILE_SYNCHRONOUS_IO_ALERT |
2623                                FILE_SYNCHRONOUS_IO_NONALERT |
2624                                FILE_WRITE_THROUGH |
2625                                FILE_COMPLETE_IF_OPLOCKED |
2626                                FILE_OPEN_FOR_BACKUP_INTENT |
2627                                FILE_DELETE_ON_CLOSE |
2628                                FILE_OPEN_FOR_FREE_SPACE_QUERY |
2629                                FILE_OPEN_BY_FILE_ID |
2630                                FILE_NO_COMPRESSION |
2631                                FILE_OPEN_REPARSE_POINT)))
2632         {
2633             DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2634             return STATUS_INVALID_PARAMETER;
2635         }
2636 
2637         if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2638             (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
2639         {
2640             DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2641             return STATUS_INVALID_PARAMETER;
2642         }
2643 
2644         if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
2645         {
2646             DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2647             return STATUS_INVALID_PARAMETER;
2648         }
2649 
2650         if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
2651         {
2652             DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2653             return STATUS_INVALID_PARAMETER;
2654         }
2655 
2656         /* Now check if this is a named pipe */
2657         if (CreateFileType == CreateFileTypeNamedPipe)
2658         {
2659             /* Make sure we have extra parameters */
2660             if (!ExtraCreateParameters)
2661             {
2662                 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2663                 return STATUS_INVALID_PARAMETER;
2664             }
2665 
2666             /* Get the parameters and validate them */
2667             NamedPipeCreateParameters = ExtraCreateParameters;
2668             if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
2669                 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
2670                 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
2671                 (ShareAccess & FILE_SHARE_DELETE) ||
2672                 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
2673                 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
2674             {
2675                 /* Invalid named pipe create */
2676                 DPRINT1("Invalid named pipe create\n");
2677                 return STATUS_INVALID_PARAMETER;
2678             }
2679         }
2680         else if (CreateFileType == CreateFileTypeMailslot)
2681         {
2682             /* Make sure we have extra parameters */
2683             if (!ExtraCreateParameters)
2684             {
2685                 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2686                 return STATUS_INVALID_PARAMETER;
2687             }
2688 
2689             /* Get the parameters and validate them */
2690             if ((ShareAccess & FILE_SHARE_DELETE) ||
2691                 !(ShareAccess & ~FILE_SHARE_WRITE) ||
2692                 (Disposition != FILE_CREATE) ||
2693                 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
2694             {
2695                 /* Invalid mailslot create */
2696                 DPRINT1("Invalid mailslot create\n");
2697                 return STATUS_INVALID_PARAMETER;
2698             }
2699         }
2700     }
2701 
2702     /* Allocate the open packet */
2703     OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
2704     if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
2705     RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
2706 
2707     /* Check if the call came from user mode */
2708     if (AccessMode != KernelMode)
2709     {
2710         _SEH2_TRY
2711         {
2712             /* Probe the output parameters */
2713             ProbeForWriteHandle(FileHandle);
2714             ProbeForWriteIoStatusBlock(IoStatusBlock);
2715 
2716             /* Probe the allocation size if one was passed in */
2717             if (AllocationSize)
2718             {
2719                 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
2720             }
2721             else
2722             {
2723                 SafeAllocationSize.QuadPart = 0;
2724             }
2725 
2726             /* Make sure it's valid */
2727             if (SafeAllocationSize.QuadPart < 0)
2728             {
2729                 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
2730             }
2731 
2732             /* Check if EA was passed in */
2733             if ((EaBuffer) && (EaLength))
2734             {
2735                 /* Probe it */
2736                 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
2737 
2738                 /* And marshall it */
2739                 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2740                                                              EaLength,
2741                                                              TAG_EA);
2742                 OpenPacket->EaLength = EaLength;
2743                 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2744 
2745                 /* Validate the buffer */
2746                 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2747                                                  EaLength,
2748                                                  &EaErrorOffset);
2749                 if (!NT_SUCCESS(Status))
2750                 {
2751                     /* Undo everything if it's invalid */
2752                     DPRINT1("Invalid EA buffer\n");
2753                     IoStatusBlock->Status = Status;
2754                     IoStatusBlock->Information = EaErrorOffset;
2755                     RtlRaiseStatus(Status);
2756                 }
2757             }
2758         }
2759         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2760         {
2761             /* Return the exception code */
2762             if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
2763             ExFreePool(OpenPacket);
2764             _SEH2_YIELD(return _SEH2_GetExceptionCode());
2765         }
2766         _SEH2_END;
2767     }
2768     else
2769     {
2770         /* Check if this is a device attach */
2771         if (CreateOptions & IO_ATTACH_DEVICE_API)
2772         {
2773             /* Set the flag properly */
2774             Options |= IO_ATTACH_DEVICE;
2775             CreateOptions &= ~IO_ATTACH_DEVICE_API;
2776         }
2777 
2778         /* Check if we have allocation size */
2779         if (AllocationSize)
2780         {
2781             /* Capture it */
2782             SafeAllocationSize = *AllocationSize;
2783         }
2784         else
2785         {
2786             /* Otherwise, no size */
2787             SafeAllocationSize.QuadPart = 0;
2788         }
2789 
2790         /* Check if we have an EA packet */
2791         if ((EaBuffer) && (EaLength))
2792         {
2793             /* Allocate the kernel copy */
2794             OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2795                                                          EaLength,
2796                                                          TAG_EA);
2797             if (!OpenPacket->EaBuffer)
2798             {
2799                 ExFreePool(OpenPacket);
2800                 DPRINT1("Failed to allocate open packet EA buffer\n");
2801                 return STATUS_INSUFFICIENT_RESOURCES;
2802             }
2803 
2804             /* Copy the data */
2805             OpenPacket->EaLength = EaLength;
2806             RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2807 
2808             /* Validate the buffer */
2809             Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2810                                              EaLength,
2811                                              &EaErrorOffset);
2812             if (!NT_SUCCESS(Status))
2813             {
2814                 /* Undo everything if it's invalid */
2815                 DPRINT1("Invalid EA buffer\n");
2816                 ExFreePool(OpenPacket->EaBuffer);
2817                 IoStatusBlock->Status = Status;
2818                 IoStatusBlock->Information = EaErrorOffset;
2819                 ExFreePool(OpenPacket);
2820                 return Status;
2821             }
2822         }
2823     }
2824 
2825     /* Setup the Open Packet */
2826     OpenPacket->Type = IO_TYPE_OPEN_PACKET;
2827     OpenPacket->Size = sizeof(*OpenPacket);
2828     OpenPacket->AllocationSize = SafeAllocationSize;
2829     OpenPacket->CreateOptions = CreateOptions;
2830     OpenPacket->FileAttributes = (USHORT)FileAttributes;
2831     OpenPacket->ShareAccess = (USHORT)ShareAccess;
2832     OpenPacket->Options = Options;
2833     OpenPacket->Disposition = Disposition;
2834     OpenPacket->CreateFileType = CreateFileType;
2835     OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
2836     OpenPacket->InternalFlags = Flags;
2837     OpenPacket->TopDeviceObjectHint = DeviceObject;
2838 
2839     /* Update the operation count */
2840     IopUpdateOperationCount(IopOtherTransfer);
2841 
2842     /*
2843      * Attempt opening the file. This will call the I/O Parse Routine for
2844      * the File Object (IopParseDevice) which will create the object and
2845      * send the IRP to its device object. Note that we have two statuses
2846      * to worry about: the Object Manager's status (in Status) and the I/O
2847      * status, which is in the Open Packet's Final Status, and determined
2848      * by the Parse Check member.
2849      */
2850     Status = ObOpenObjectByName(ObjectAttributes,
2851                                 NULL,
2852                                 AccessMode,
2853                                 NULL,
2854                                 DesiredAccess,
2855                                 OpenPacket,
2856                                 &LocalHandle);
2857 
2858     /* Free the EA Buffer */
2859     if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2860 
2861     /* Now check for Ob or Io failure */
2862     if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
2863     {
2864         /* Check if Ob thinks well went well */
2865         if (NT_SUCCESS(Status))
2866         {
2867             /*
2868              * Tell it otherwise. Because we didn't use an ObjectType,
2869              * it incorrectly returned us a handle to God knows what.
2870              */
2871             ZwClose(LocalHandle);
2872             Status = STATUS_OBJECT_TYPE_MISMATCH;
2873         }
2874 
2875         /* Now check the Io status */
2876         if (!NT_SUCCESS(OpenPacket->FinalStatus))
2877         {
2878             /* Use this status instead of Ob's */
2879             Status = OpenPacket->FinalStatus;
2880 
2881             /* Check if it was only a warning */
2882             if (NT_WARNING(Status))
2883             {
2884                 /* Protect write with SEH */
2885                 _SEH2_TRY
2886                 {
2887                     /* In this case, we copy the I/O Status back */
2888                     IoStatusBlock->Information = OpenPacket->Information;
2889                     IoStatusBlock->Status = OpenPacket->FinalStatus;
2890                 }
2891                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2892                 {
2893                     /* Get exception code */
2894                     Status = _SEH2_GetExceptionCode();
2895                 }
2896                 _SEH2_END;
2897             }
2898         }
2899         else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
2900         {
2901             /*
2902              * This can happen in the very bizarre case where the parse routine
2903              * actually executed more then once (due to a reparse) and ended
2904              * up failing after already having created the File Object.
2905              */
2906             if (OpenPacket->FileObject->FileName.Length)
2907             {
2908                 /* It had a name, free it */
2909                 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2910             }
2911 
2912             /* Clear the device object to invalidate the FO, and dereference */
2913             OpenPacket->FileObject->DeviceObject = NULL;
2914             ObDereferenceObject(OpenPacket->FileObject);
2915         }
2916     }
2917     else
2918     {
2919         /* We reached success and have a valid file handle */
2920         OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2921         ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2922 
2923         /* Enter SEH for write back */
2924         _SEH2_TRY
2925         {
2926             /* Write back the handle and I/O Status */
2927             *FileHandle = LocalHandle;
2928             IoStatusBlock->Information = OpenPacket->Information;
2929             IoStatusBlock->Status = OpenPacket->FinalStatus;
2930 
2931             /* Get the Io status */
2932             Status = OpenPacket->FinalStatus;
2933         }
2934         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2935         {
2936             /* Get the exception status */
2937             Status = _SEH2_GetExceptionCode();
2938         }
2939         _SEH2_END;
2940     }
2941 
2942     /* Check if we were 100% successful */
2943     if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
2944     {
2945         /* Dereference the File Object */
2946         ObDereferenceObject(OpenPacket->FileObject);
2947     }
2948 
2949     /* Return status */
2950     ExFreePool(OpenPacket);
2951     return Status;
2952 }
2953 
2954 /* FUNCTIONS *****************************************************************/
2955 
2956 /*
2957  * @unimplemented
2958  */
2959 NTSTATUS
2960 NTAPI
2961 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
2962                                IN ULONG Length,
2963                                IN BOOLEAN SetOperation)
2964 {
2965     UNIMPLEMENTED;
2966     return STATUS_NOT_IMPLEMENTED;
2967 }
2968 
2969 /*
2970  * @unimplemented
2971  */
2972 NTSTATUS
2973 NTAPI
2974 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
2975                            IN ULONG QuotaLength,
2976                            OUT PULONG ErrorOffset)
2977 {
2978     UNIMPLEMENTED;
2979     return STATUS_NOT_IMPLEMENTED;
2980 }
2981 
2982 /*
2983  * @implemented
2984  */
2985 NTSTATUS
2986 NTAPI
2987 IoCreateFile(OUT PHANDLE FileHandle,
2988              IN ACCESS_MASK DesiredAccess,
2989              IN POBJECT_ATTRIBUTES ObjectAttributes,
2990              OUT PIO_STATUS_BLOCK IoStatusBlock,
2991              IN PLARGE_INTEGER AllocationSize OPTIONAL,
2992              IN ULONG FileAttributes,
2993              IN ULONG ShareAccess,
2994              IN ULONG Disposition,
2995              IN ULONG CreateOptions,
2996              IN PVOID EaBuffer OPTIONAL,
2997              IN ULONG EaLength,
2998              IN CREATE_FILE_TYPE CreateFileType,
2999              IN PVOID ExtraCreateParameters OPTIONAL,
3000              IN ULONG Options)
3001 {
3002     PAGED_CODE();
3003 
3004     return IopCreateFile(FileHandle,
3005                          DesiredAccess,
3006                          ObjectAttributes,
3007                          IoStatusBlock,
3008                          AllocationSize,
3009                          FileAttributes,
3010                          ShareAccess,
3011                          Disposition,
3012                          CreateOptions,
3013                          EaBuffer,
3014                          EaLength,
3015                          CreateFileType,
3016                          ExtraCreateParameters,
3017                          Options,
3018                          0,
3019                          NULL);
3020 }
3021 
3022 /*
3023  * @unimplemented
3024  */
3025 NTSTATUS
3026 NTAPI
3027 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
3028                                     IN ACCESS_MASK DesiredAccess,
3029                                     IN POBJECT_ATTRIBUTES ObjectAttributes,
3030                                     OUT PIO_STATUS_BLOCK IoStatusBlock,
3031                                     IN PLARGE_INTEGER AllocationSize OPTIONAL,
3032                                     IN ULONG FileAttributes,
3033                                     IN ULONG ShareAccess,
3034                                     IN ULONG Disposition,
3035                                     IN ULONG CreateOptions,
3036                                     IN PVOID EaBuffer OPTIONAL,
3037                                     IN ULONG EaLength,
3038                                     IN CREATE_FILE_TYPE CreateFileType,
3039                                     IN PVOID ExtraCreateParameters OPTIONAL,
3040                                     IN ULONG Options,
3041                                     IN PVOID DeviceObject)
3042 {
3043     ULONG Flags = 0;
3044 
3045     PAGED_CODE();
3046 
3047     /* Check if we were passed a device to send the create request to*/
3048     if (DeviceObject)
3049     {
3050         /* We'll tag this request into a file object extension */
3051         Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
3052     }
3053 
3054     return IopCreateFile(FileHandle,
3055                          DesiredAccess,
3056                          ObjectAttributes,
3057                          IoStatusBlock,
3058                          AllocationSize,
3059                          FileAttributes,
3060                          ShareAccess,
3061                          Disposition,
3062                          CreateOptions,
3063                          EaBuffer,
3064                          EaLength,
3065                          CreateFileType,
3066                          ExtraCreateParameters,
3067                          Options | IO_NO_PARAMETER_CHECKING,
3068                          Flags,
3069                          DeviceObject);
3070 }
3071 
3072 /*
3073  * @implemented
3074  */
3075 PFILE_OBJECT
3076 NTAPI
3077 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
3078                            IN PDEVICE_OBJECT DeviceObject OPTIONAL,
3079                            OUT PHANDLE FileObjectHandle OPTIONAL)
3080 {
3081     PFILE_OBJECT CreatedFileObject;
3082     NTSTATUS Status;
3083     HANDLE FileHandle;
3084     OBJECT_ATTRIBUTES ObjectAttributes;
3085     PAGED_CODE();
3086     IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3087 
3088     /* Choose Device Object */
3089     if (FileObject) DeviceObject = FileObject->DeviceObject;
3090 
3091     /* Reference the device object and initialize attributes */
3092     InterlockedIncrement(&DeviceObject->ReferenceCount);
3093     InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3094 
3095     /* Create the File Object */
3096     Status = ObCreateObject(KernelMode,
3097                             IoFileObjectType,
3098                             &ObjectAttributes,
3099                             KernelMode,
3100                             NULL,
3101                             sizeof(FILE_OBJECT),
3102                             sizeof(FILE_OBJECT),
3103                             0,
3104                             (PVOID*)&CreatedFileObject);
3105     if (!NT_SUCCESS(Status))
3106     {
3107         /* Fail */
3108         IopDereferenceDeviceObject(DeviceObject, FALSE);
3109         ExRaiseStatus(Status);
3110     }
3111 
3112     /* Set File Object Data */
3113     RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3114     CreatedFileObject->DeviceObject = DeviceObject;
3115     CreatedFileObject->Type = IO_TYPE_FILE;
3116     CreatedFileObject->Size = sizeof(FILE_OBJECT);
3117     CreatedFileObject->Flags = FO_STREAM_FILE;
3118 
3119     /* Initialize the wait event */
3120     KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3121 
3122     /* Insert it to create a handle for it */
3123     Status = ObInsertObject(CreatedFileObject,
3124                             NULL,
3125                             FILE_READ_DATA,
3126                             1,
3127                             (PVOID*)&CreatedFileObject,
3128                             &FileHandle);
3129     if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
3130 
3131     /* Set the handle created flag */
3132     CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3133     ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3134 
3135     /* Check if we have a VPB */
3136     if (DeviceObject->Vpb)
3137     {
3138         /* Reference it */
3139          InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3140     }
3141 
3142     /* Check if the caller wants the handle */
3143     if (FileObjectHandle)
3144     {
3145         /* Return it */
3146         *FileObjectHandle = FileHandle;
3147         ObDereferenceObject(CreatedFileObject);
3148     }
3149     else
3150     {
3151         /* Otherwise, close it */
3152         ObCloseHandle(FileHandle, KernelMode);
3153     }
3154 
3155     /* Return the file object */
3156     return CreatedFileObject;
3157 }
3158 
3159 /*
3160  * @implemented
3161  */
3162 PFILE_OBJECT
3163 NTAPI
3164 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
3165                          IN PDEVICE_OBJECT DeviceObject)
3166 {
3167     /* Call the newer function */
3168     return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
3169 }
3170 
3171 /*
3172  * @implemented
3173  */
3174 PFILE_OBJECT
3175 NTAPI
3176 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
3177                              IN PDEVICE_OBJECT DeviceObject OPTIONAL)
3178 {
3179     PFILE_OBJECT CreatedFileObject;
3180     NTSTATUS Status;
3181     OBJECT_ATTRIBUTES ObjectAttributes;
3182     PAGED_CODE();
3183     IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3184 
3185     /* Choose Device Object */
3186     if (FileObject) DeviceObject = FileObject->DeviceObject;
3187 
3188     /* Reference the device object and initialize attributes */
3189     InterlockedIncrement(&DeviceObject->ReferenceCount);
3190     InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3191 
3192     /* Create the File Object */
3193     Status = ObCreateObject(KernelMode,
3194                             IoFileObjectType,
3195                             &ObjectAttributes,
3196                             KernelMode,
3197                             NULL,
3198                             sizeof(FILE_OBJECT),
3199                             sizeof(FILE_OBJECT),
3200                             0,
3201                             (PVOID*)&CreatedFileObject);
3202     if (!NT_SUCCESS(Status))
3203     {
3204         /* Fail */
3205         IopDereferenceDeviceObject(DeviceObject, FALSE);
3206         ExRaiseStatus(Status);
3207     }
3208 
3209     /* Set File Object Data */
3210     RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3211     CreatedFileObject->DeviceObject = DeviceObject;
3212     CreatedFileObject->Type = IO_TYPE_FILE;
3213     CreatedFileObject->Size = sizeof(FILE_OBJECT);
3214     CreatedFileObject->Flags = FO_STREAM_FILE;
3215 
3216     /* Initialize the wait event */
3217     KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3218 
3219     /* Destroy create information */
3220     ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
3221                                  ObjectCreateInfo);
3222     OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
3223 
3224     /* Set the handle created flag */
3225     CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3226     ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3227 
3228     /* Check if we have a VPB */
3229     if (DeviceObject->Vpb)
3230     {
3231         /* Reference it */
3232          InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3233     }
3234 
3235     /* Return the file object */
3236     return CreatedFileObject;
3237 }
3238 
3239 /*
3240  * @implemented
3241  */
3242 PGENERIC_MAPPING
3243 NTAPI
3244 IoGetFileObjectGenericMapping(VOID)
3245 {
3246     /* Return the mapping */
3247     return &IopFileMapping;
3248 }
3249 
3250 /*
3251  * @implemented
3252  */
3253 BOOLEAN
3254 NTAPI
3255 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
3256 {
3257     /* Return the flag status */
3258     return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3259 }
3260 
3261 /*
3262  * @implemented
3263  */
3264 BOOLEAN
3265 NTAPI
3266 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
3267                              IN ACCESS_MASK DesiredAccess,
3268                              IN ULONG OpenOptions,
3269                              OUT PIO_STATUS_BLOCK IoStatus,
3270                              OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
3271 {
3272     NTSTATUS Status;
3273     DUMMY_FILE_OBJECT LocalFileObject;
3274     HANDLE Handle;
3275     OPEN_PACKET OpenPacket;
3276     PAGED_CODE();
3277     IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
3278 
3279     /* Setup the Open Packet */
3280     RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3281     OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3282     OpenPacket.Size = sizeof(OPEN_PACKET);
3283     OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
3284     OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
3285     OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
3286     OpenPacket.Disposition = FILE_OPEN;
3287     OpenPacket.NetworkInformation = Buffer;
3288     OpenPacket.QueryOnly = TRUE;
3289     OpenPacket.FullAttributes = TRUE;
3290     OpenPacket.LocalFileObject = &LocalFileObject;
3291 
3292     /*
3293      * Attempt opening the file. This will call the I/O Parse Routine for
3294      * the File Object (IopParseDevice) which will use the dummy file obejct
3295      * send the IRP to its device object. Note that we have two statuses
3296      * to worry about: the Object Manager's status (in Status) and the I/O
3297      * status, which is in the Open Packet's Final Status, and determined
3298      * by the Parse Check member.
3299      */
3300     Status = ObOpenObjectByName(ObjectAttributes,
3301                                 NULL,
3302                                 KernelMode,
3303                                 NULL,
3304                                 DesiredAccess,
3305                                 &OpenPacket,
3306                                 &Handle);
3307     if (OpenPacket.ParseCheck == FALSE)
3308     {
3309         /* Parse failed */
3310         IoStatus->Status = Status;
3311     }
3312     else
3313     {
3314         /* Use the Io status */
3315         IoStatus->Status = OpenPacket.FinalStatus;
3316         IoStatus->Information = OpenPacket.Information;
3317     }
3318 
3319     /* Return success */
3320     return TRUE;
3321 }
3322 
3323 /*
3324  * @implemented
3325  */
3326 VOID
3327 NTAPI
3328 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
3329                     OUT PSHARE_ACCESS ShareAccess)
3330 {
3331     PAGED_CODE();
3332 
3333     /* Check if the file has an extension */
3334     if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3335     {
3336         /* Check if caller specified to ignore access checks */
3337         //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3338         {
3339             /* Don't update share access */
3340             return;
3341         }
3342     }
3343 
3344     /* Otherwise, check if there's any access present */
3345     if ((FileObject->ReadAccess) ||
3346         (FileObject->WriteAccess) ||
3347         (FileObject->DeleteAccess))
3348     {
3349         /* Increase the open count */
3350         ShareAccess->OpenCount++;
3351 
3352         /* Add new share access */
3353         ShareAccess->Readers += FileObject->ReadAccess;
3354         ShareAccess->Writers += FileObject->WriteAccess;
3355         ShareAccess->Deleters += FileObject->DeleteAccess;
3356         ShareAccess->SharedRead += FileObject->SharedRead;
3357         ShareAccess->SharedWrite += FileObject->SharedWrite;
3358         ShareAccess->SharedDelete += FileObject->SharedDelete;
3359     }
3360 }
3361 
3362 /*
3363  * @implemented
3364  */
3365 NTSTATUS
3366 NTAPI
3367 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
3368                    IN ULONG DesiredShareAccess,
3369                    IN PFILE_OBJECT FileObject,
3370                    IN PSHARE_ACCESS ShareAccess,
3371                    IN BOOLEAN Update)
3372 {
3373     BOOLEAN ReadAccess;
3374     BOOLEAN WriteAccess;
3375     BOOLEAN DeleteAccess;
3376     BOOLEAN SharedRead;
3377     BOOLEAN SharedWrite;
3378     BOOLEAN SharedDelete;
3379     PAGED_CODE();
3380 
3381     /* Get access masks */
3382     ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3383     WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3384     DeleteAccess = (DesiredAccess & DELETE) != 0;
3385 
3386     /* Set them in the file object */
3387     FileObject->ReadAccess = ReadAccess;
3388     FileObject->WriteAccess = WriteAccess;
3389     FileObject->DeleteAccess = DeleteAccess;
3390 
3391     /* Check if the file has an extension */
3392     if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3393     {
3394         /* Check if caller specified to ignore access checks */
3395         //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3396         {
3397             /* Don't check share access */
3398             return STATUS_SUCCESS;
3399         }
3400     }
3401 
3402     /* Check if we have any access */
3403     if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
3404     {
3405         /* Get shared access masks */
3406         SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3407         SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3408         SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3409 
3410         /* Set them */
3411         FileObject->SharedRead = SharedRead;
3412         FileObject->SharedWrite = SharedWrite;
3413         FileObject->SharedDelete = SharedDelete;
3414 
3415         /* Check if the shared access is violated */
3416         if ((ReadAccess &&
3417              (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
3418             (WriteAccess &&
3419              (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
3420             (DeleteAccess &&
3421              (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
3422             ((ShareAccess->Readers != 0) && !SharedRead) ||
3423             ((ShareAccess->Writers != 0) && !SharedWrite) ||
3424             ((ShareAccess->Deleters != 0) && !SharedDelete))
3425         {
3426             /* Sharing violation, fail */
3427             return STATUS_SHARING_VIOLATION;
3428         }
3429 
3430         /* It's not, check if caller wants us to update it */
3431         if (Update)
3432         {
3433             /* Increase open count */
3434             ShareAccess->OpenCount++;
3435 
3436             /* Update shared access */
3437             ShareAccess->Readers += ReadAccess;
3438             ShareAccess->Writers += WriteAccess;
3439             ShareAccess->Deleters += DeleteAccess;
3440             ShareAccess->SharedRead += SharedRead;
3441             ShareAccess->SharedWrite += SharedWrite;
3442             ShareAccess->SharedDelete += SharedDelete;
3443         }
3444     }
3445 
3446     /* Validation successful */
3447     return STATUS_SUCCESS;
3448 }
3449 
3450 /*
3451  * @implemented
3452  */
3453 VOID
3454 NTAPI
3455 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
3456                     IN PSHARE_ACCESS ShareAccess)
3457 {
3458     PAGED_CODE();
3459 
3460     /* Check if the file has an extension */
3461     if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3462     {
3463         /* Check if caller specified to ignore access checks */
3464         //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3465         {
3466             /* Don't update share access */
3467             return;
3468         }
3469     }
3470 
3471     /* Otherwise, check if there's any access present */
3472     if ((FileObject->ReadAccess) ||
3473         (FileObject->WriteAccess) ||
3474         (FileObject->DeleteAccess))
3475     {
3476         /* Decrement the open count */
3477         ShareAccess->OpenCount--;
3478 
3479         /* Remove share access */
3480         ShareAccess->Readers -= FileObject->ReadAccess;
3481         ShareAccess->Writers -= FileObject->WriteAccess;
3482         ShareAccess->Deleters -= FileObject->DeleteAccess;
3483         ShareAccess->SharedRead -= FileObject->SharedRead;
3484         ShareAccess->SharedWrite -= FileObject->SharedWrite;
3485         ShareAccess->SharedDelete -= FileObject->SharedDelete;
3486     }
3487 }
3488 
3489 /*
3490  * @implemented
3491  */
3492 VOID
3493 NTAPI
3494 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
3495                  IN ULONG DesiredShareAccess,
3496                  IN PFILE_OBJECT FileObject,
3497                  OUT PSHARE_ACCESS ShareAccess)
3498 {
3499     BOOLEAN ReadAccess;
3500     BOOLEAN WriteAccess;
3501     BOOLEAN DeleteAccess;
3502     BOOLEAN SharedRead;
3503     BOOLEAN SharedWrite;
3504     BOOLEAN SharedDelete;
3505     BOOLEAN Update = TRUE;
3506     PAGED_CODE();
3507 
3508     ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3509     WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3510     DeleteAccess = (DesiredAccess & DELETE) != 0;
3511 
3512     /* Check if the file has an extension */
3513     if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3514     {
3515         /* Check if caller specified to ignore access checks */
3516         //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3517         {
3518             /* Don't update share access */
3519             Update = FALSE;
3520         }
3521     }
3522 
3523     /* Update basic access */
3524     FileObject->ReadAccess = ReadAccess;
3525     FileObject->WriteAccess = WriteAccess;
3526     FileObject->DeleteAccess = DeleteAccess;
3527 
3528     /* Check if we have no access as all */
3529     if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
3530     {
3531         /* Check if we need to update the structure */
3532         if (!Update) return;
3533 
3534         /* Otherwise, clear data */
3535         ShareAccess->OpenCount = 0;
3536         ShareAccess->Readers = 0;
3537         ShareAccess->Writers = 0;
3538         ShareAccess->Deleters = 0;
3539         ShareAccess->SharedRead = 0;
3540         ShareAccess->SharedWrite = 0;
3541         ShareAccess->SharedDelete = 0;
3542     }
3543     else
3544     {
3545         /* Calculate shared access */
3546         SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3547         SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3548         SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3549 
3550         /* Set it in the FO */
3551         FileObject->SharedRead = SharedRead;
3552         FileObject->SharedWrite = SharedWrite;
3553         FileObject->SharedDelete = SharedDelete;
3554 
3555         /* Check if we need to update the structure */
3556         if (!Update) return;
3557 
3558         /* Otherwise, set data */
3559         ShareAccess->OpenCount = 1;
3560         ShareAccess->Readers = ReadAccess;
3561         ShareAccess->Writers = WriteAccess;
3562         ShareAccess->Deleters = DeleteAccess;
3563         ShareAccess->SharedRead = SharedRead;
3564         ShareAccess->SharedWrite = SharedWrite;
3565         ShareAccess->SharedDelete = SharedDelete;
3566     }
3567 }
3568 
3569 /*
3570  * @implemented
3571  */
3572 VOID
3573 NTAPI
3574 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
3575                  IN PFILE_OBJECT FileObject)
3576 {
3577     PIRP Irp;
3578     KEVENT Event;
3579     KIRQL OldIrql;
3580     NTSTATUS Status;
3581     PIO_STACK_LOCATION Stack;
3582 
3583     /* Check if handles were already created for the
3584      * open file. If so, that's over.
3585      */
3586     if (FileObject->Flags & FO_HANDLE_CREATED)
3587         KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
3588                      (ULONG_PTR)FileObject,
3589                      (ULONG_PTR)DeviceObject, 0, 0);
3590 
3591     /* Reset the events */
3592     KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
3593     KeClearEvent(&FileObject->Event);
3594 
3595     /* Allocate the IRP we'll use */
3596     Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
3597     /* Properly set it */
3598     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3599     Irp->UserEvent = &Event;
3600     Irp->UserIosb = &Irp->IoStatus;
3601     Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3602     Irp->Tail.Overlay.OriginalFileObject = FileObject;
3603     Irp->RequestorMode = KernelMode;
3604     Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
3605 
3606     Stack = IoGetNextIrpStackLocation(Irp);
3607     Stack->MajorFunction = IRP_MJ_CLEANUP;
3608     Stack->FileObject = FileObject;
3609 
3610     /* Put on top of IRPs list of the thread */
3611     IopQueueIrpToThread(Irp);
3612 
3613     /* Call the driver */
3614     Status = IoCallDriver(DeviceObject, Irp);
3615     if (Status == STATUS_PENDING)
3616     {
3617         KeWaitForSingleObject(&Event, UserRequest,
3618                               KernelMode, FALSE, NULL);
3619     }
3620 
3621     /* Remove from IRPs list */
3622     KeRaiseIrql(APC_LEVEL, &OldIrql);
3623     IopUnQueueIrpFromThread(Irp);
3624     KeLowerIrql(OldIrql);
3625 
3626     /* Free the IRP */
3627     IoFreeIrp(Irp);
3628 
3629     /* Clear the event */
3630     KeClearEvent(&FileObject->Event);
3631     /* And finally, mark the open operation as canceled */
3632     FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
3633 }
3634 
3635 /*
3636  * @implemented
3637  */
3638 NTSTATUS
3639 NTAPI
3640 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
3641                          OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
3642 {
3643     NTSTATUS Status;
3644     ULONG Length, ReturnLength;
3645     POBJECT_NAME_INFORMATION LocalInfo;
3646 
3647     /* Start with a buffer length of 200 */
3648     ReturnLength = 200;
3649     /*
3650      * We'll loop until query works.
3651      * We will use returned length for next loop
3652      * iteration, trying to have a big enough buffer.
3653      */
3654     for (Length = 200; ; Length = ReturnLength)
3655     {
3656         /* Allocate our work buffer */
3657         LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, 'nDoI');
3658         if (LocalInfo == NULL)
3659         {
3660             return STATUS_INSUFFICIENT_RESOURCES;
3661         }
3662 
3663         /* Query the DOS name */
3664         Status = IopQueryNameInternal(FileObject,
3665                                       TRUE,
3666                                       TRUE,
3667                                       LocalInfo,
3668                                       Length,
3669                                       &ReturnLength,
3670                                       KernelMode);
3671         /* If it succeed, nothing more to do */
3672         if (Status == STATUS_SUCCESS)
3673         {
3674             break;
3675         }
3676 
3677         /* Otherwise, prepare for re-allocation */
3678         ExFreePoolWithTag(LocalInfo, 'nDoI');
3679 
3680         /*
3681          * If we failed because of something else
3682          * than memory, simply stop and fail here
3683          */
3684         if (Status != STATUS_BUFFER_OVERFLOW)
3685         {
3686             return Status;
3687         }
3688     }
3689 
3690     /* Success case here: return our buffer */
3691     *ObjectNameInformation = LocalInfo;
3692     return STATUS_SUCCESS;
3693 }
3694 
3695 /*
3696  * @implemented
3697  */
3698 NTSTATUS
3699 NTAPI
3700 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
3701                 IN BOOLEAN Remote)
3702 {
3703     NTSTATUS Status = STATUS_SUCCESS;
3704     BOOLEAN FlagSet;
3705 
3706     /* Get the flag status */
3707     FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3708 
3709     /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3710     if (Remote && !FlagSet)
3711     {
3712         /* Set the flag */
3713         FileObject->Flags |= FO_REMOTE_ORIGIN;
3714     }
3715     else if (!Remote && FlagSet)
3716     {
3717         /* Remove the flag */
3718         FileObject->Flags &= ~FO_REMOTE_ORIGIN;
3719     }
3720     else
3721     {
3722         /* Fail */
3723         Status = STATUS_INVALID_PARAMETER_MIX;
3724     }
3725 
3726     /* Return status */
3727     return Status;
3728 }
3729 
3730 /*
3731  * @implemented
3732  */
3733 NTSTATUS
3734 NTAPI
3735 NtCreateFile(PHANDLE FileHandle,
3736              ACCESS_MASK DesiredAccess,
3737              POBJECT_ATTRIBUTES ObjectAttributes,
3738              PIO_STATUS_BLOCK IoStatusBlock,
3739              PLARGE_INTEGER AllocateSize,
3740              ULONG FileAttributes,
3741              ULONG ShareAccess,
3742              ULONG CreateDisposition,
3743              ULONG CreateOptions,
3744              PVOID EaBuffer,
3745              ULONG EaLength)
3746 {
3747     /* Call the I/O Function */
3748     return IoCreateFile(FileHandle,
3749                         DesiredAccess,
3750                         ObjectAttributes,
3751                         IoStatusBlock,
3752                         AllocateSize,
3753                         FileAttributes,
3754                         ShareAccess,
3755                         CreateDisposition,
3756                         CreateOptions,
3757                         EaBuffer,
3758                         EaLength,
3759                         CreateFileTypeNone,
3760                         NULL,
3761                         0);
3762 }
3763 
3764 NTSTATUS
3765 NTAPI
3766 NtCreateMailslotFile(OUT PHANDLE FileHandle,
3767                      IN ACCESS_MASK DesiredAccess,
3768                      IN POBJECT_ATTRIBUTES ObjectAttributes,
3769                      OUT PIO_STATUS_BLOCK IoStatusBlock,
3770                      IN ULONG CreateOptions,
3771                      IN ULONG MailslotQuota,
3772                      IN ULONG MaxMessageSize,
3773                      IN PLARGE_INTEGER TimeOut)
3774 {
3775     MAILSLOT_CREATE_PARAMETERS Buffer;
3776     PAGED_CODE();
3777 
3778     /* Check for Timeout */
3779     if (TimeOut)
3780     {
3781         /* check if the call came from user mode */
3782         if (KeGetPreviousMode() != KernelMode)
3783         {
3784             /* Enter SEH for Probe */
3785             _SEH2_TRY
3786             {
3787                 /* Probe the timeout */
3788                 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
3789             }
3790             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3791             {
3792                 /* Return the exception code */
3793                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3794             }
3795             _SEH2_END;
3796         }
3797         else
3798         {
3799             /* Otherwise, capture directly */
3800             Buffer.ReadTimeout = *TimeOut;
3801         }
3802 
3803         /* Set the correct setting */
3804         Buffer.TimeoutSpecified = TRUE;
3805     }
3806     else
3807     {
3808         /* Tell the FSD we don't have a timeout */
3809         Buffer.TimeoutSpecified = FALSE;
3810     }
3811 
3812     /* Set Settings */
3813     Buffer.MailslotQuota = MailslotQuota;
3814     Buffer.MaximumMessageSize = MaxMessageSize;
3815 
3816     /* Call I/O */
3817     return IoCreateFile(FileHandle,
3818                         DesiredAccess,
3819                         ObjectAttributes,
3820                         IoStatusBlock,
3821                         NULL,
3822                         0,
3823                         FILE_SHARE_READ | FILE_SHARE_WRITE,
3824                         FILE_CREATE,
3825                         CreateOptions,
3826                         NULL,
3827                         0,
3828                         CreateFileTypeMailslot,
3829                         (PVOID)&Buffer,
3830                         0);
3831 }
3832 
3833 NTSTATUS
3834 NTAPI
3835 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
3836                       IN ACCESS_MASK DesiredAccess,
3837                       IN POBJECT_ATTRIBUTES ObjectAttributes,
3838                       OUT PIO_STATUS_BLOCK IoStatusBlock,
3839                       IN ULONG ShareAccess,
3840                       IN ULONG CreateDisposition,
3841                       IN ULONG CreateOptions,
3842                       IN ULONG NamedPipeType,
3843                       IN ULONG ReadMode,
3844                       IN ULONG CompletionMode,
3845                       IN ULONG MaximumInstances,
3846                       IN ULONG InboundQuota,
3847                       IN ULONG OutboundQuota,
3848                       IN PLARGE_INTEGER DefaultTimeout)
3849 {
3850     NAMED_PIPE_CREATE_PARAMETERS Buffer;
3851     PAGED_CODE();
3852 
3853     /* Check for Timeout */
3854     if (DefaultTimeout)
3855     {
3856         /* check if the call came from user mode */
3857         if (KeGetPreviousMode() != KernelMode)
3858         {
3859             /* Enter SEH for Probe */
3860             _SEH2_TRY
3861             {
3862                 /* Probe the timeout */
3863                 Buffer.DefaultTimeout =
3864                     ProbeForReadLargeInteger(DefaultTimeout);
3865             }
3866             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3867             {
3868                 /* Return the exception code */
3869                 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3870             }
3871             _SEH2_END;
3872         }
3873         else
3874         {
3875             /* Otherwise, capture directly */
3876             Buffer.DefaultTimeout = *DefaultTimeout;
3877         }
3878 
3879         /* Set the correct setting */
3880         Buffer.TimeoutSpecified = TRUE;
3881     }
3882     else
3883     {
3884         /* Tell the FSD we don't have a timeout */
3885         Buffer.TimeoutSpecified = FALSE;
3886     }
3887 
3888     /* Set Settings */
3889     Buffer.NamedPipeType = NamedPipeType;
3890     Buffer.ReadMode = ReadMode;
3891     Buffer.CompletionMode = CompletionMode;
3892     Buffer.MaximumInstances = MaximumInstances;
3893     Buffer.InboundQuota = InboundQuota;
3894     Buffer.OutboundQuota = OutboundQuota;
3895 
3896     /* Call I/O */
3897     return IoCreateFile(FileHandle,
3898                         DesiredAccess,
3899                         ObjectAttributes,
3900                         IoStatusBlock,
3901                         NULL,
3902                         0,
3903                         ShareAccess,
3904                         CreateDisposition,
3905                         CreateOptions,
3906                         NULL,
3907                         0,
3908                         CreateFileTypeNamedPipe,
3909                         (PVOID)&Buffer,
3910                         0);
3911 }
3912 
3913 NTSTATUS
3914 NTAPI
3915 NtFlushWriteBuffer(VOID)
3916 {
3917     PAGED_CODE();
3918 
3919     /* Call the kernel */
3920     KeFlushWriteBuffer();
3921     return STATUS_SUCCESS;
3922 }
3923 
3924 /*
3925  * @implemented
3926  */
3927 NTSTATUS
3928 NTAPI
3929 NtOpenFile(OUT PHANDLE FileHandle,
3930            IN ACCESS_MASK DesiredAccess,
3931            IN POBJECT_ATTRIBUTES ObjectAttributes,
3932            OUT PIO_STATUS_BLOCK IoStatusBlock,
3933            IN ULONG ShareAccess,
3934            IN ULONG OpenOptions)
3935 {
3936     /* Call the I/O Function */
3937     return IoCreateFile(FileHandle,
3938                         DesiredAccess,
3939                         ObjectAttributes,
3940                         IoStatusBlock,
3941                         NULL,
3942                         0,
3943                         ShareAccess,
3944                         FILE_OPEN,
3945                         OpenOptions,
3946                         NULL,
3947                         0,
3948                         CreateFileTypeNone,
3949                         NULL,
3950                         0);
3951 }
3952 
3953 NTSTATUS
3954 NTAPI
3955 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3956                       OUT PFILE_BASIC_INFORMATION FileInformation)
3957 {
3958     /* Call the internal helper API */
3959     return IopQueryAttributesFile(ObjectAttributes,
3960                                   FileBasicInformation,
3961                                   sizeof(FILE_BASIC_INFORMATION),
3962                                   FileInformation);
3963 }
3964 
3965 NTSTATUS
3966 NTAPI
3967 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3968                           OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
3969 {
3970     /* Call the internal helper API */
3971     return IopQueryAttributesFile(ObjectAttributes,
3972                                   FileNetworkOpenInformation,
3973                                   sizeof(FILE_NETWORK_OPEN_INFORMATION),
3974                                   FileInformation);
3975 }
3976 
3977 /**
3978  * @name NtCancelIoFile
3979  *
3980  * Cancel all pending I/O operations in the current thread for specified
3981  * file object.
3982  *
3983  * @param FileHandle
3984  *        Handle to file object to cancel requests for. No specific
3985  *        access rights are needed.
3986  * @param IoStatusBlock
3987  *        Pointer to status block which is filled with final completition
3988  *        status on successful return.
3989  *
3990  * @return Status.
3991  *
3992  * @implemented
3993  */
3994 NTSTATUS
3995 NTAPI
3996 NtCancelIoFile(IN HANDLE FileHandle,
3997                OUT PIO_STATUS_BLOCK IoStatusBlock)
3998 {
3999     PFILE_OBJECT FileObject;
4000     PETHREAD Thread;
4001     PIRP Irp;
4002     KIRQL OldIrql;
4003     BOOLEAN OurIrpsInList = FALSE;
4004     LARGE_INTEGER Interval;
4005     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4006     NTSTATUS Status;
4007     PLIST_ENTRY ListHead, NextEntry;
4008     PAGED_CODE();
4009     IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4010 
4011     /* Check the previous mode */
4012     if (PreviousMode != KernelMode)
4013     {
4014         /* Enter SEH for probing */
4015         _SEH2_TRY
4016         {
4017             /* Probe the I/O Status Block */
4018             ProbeForWriteIoStatusBlock(IoStatusBlock);
4019         }
4020         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4021         {
4022             /* Return the exception code */
4023             _SEH2_YIELD(return _SEH2_GetExceptionCode());
4024         }
4025         _SEH2_END;
4026     }
4027 
4028     /* Reference the file object */
4029     Status = ObReferenceObjectByHandle(FileHandle,
4030                                        0,
4031                                        IoFileObjectType,
4032                                        PreviousMode,
4033                                        (PVOID*)&FileObject,
4034                                        NULL);
4035     if (!NT_SUCCESS(Status)) return Status;
4036 
4037     /* IRP cancellations are synchronized at APC_LEVEL. */
4038     KeRaiseIrql(APC_LEVEL, &OldIrql);
4039 
4040     /* Get the current thread */
4041     Thread = PsGetCurrentThread();
4042 
4043     /* Update the operation counts */
4044     IopUpdateOperationCount(IopOtherTransfer);
4045 
4046     /* Loop the list */
4047     ListHead = &Thread->IrpList;
4048     NextEntry = ListHead->Flink;
4049     while (ListHead != NextEntry)
4050     {
4051         /* Get the IRP and check if the File Object matches */
4052         Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4053         if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4054         {
4055             /* Cancel this IRP and keep looping */
4056             IoCancelIrp(Irp);
4057             OurIrpsInList = TRUE;
4058         }
4059 
4060         /* Go to the next entry */
4061         NextEntry = NextEntry->Flink;
4062     }
4063 
4064     /* Lower the IRQL */
4065     KeLowerIrql(OldIrql);
4066 
4067     /* Check if we had found an IRP */
4068     if (OurIrpsInList)
4069     {
4070         /* Setup a 10ms wait */
4071         Interval.QuadPart = -100000;
4072 
4073         /* Start looping */
4074         while (OurIrpsInList)
4075         {
4076             /* Do the wait */
4077             KeDelayExecutionThread(KernelMode, FALSE, &Interval);
4078             OurIrpsInList = FALSE;
4079 
4080             /* Raise IRQL */
4081             KeRaiseIrql(APC_LEVEL, &OldIrql);
4082 
4083             /* Now loop the list again */
4084             NextEntry = ListHead->Flink;
4085             while (NextEntry != ListHead)
4086             {
4087                 /* Get the IRP and check if the File Object matches */
4088                 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4089                 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4090                 {
4091                     /* Keep looping */
4092                     OurIrpsInList = TRUE;
4093                     break;
4094                 }
4095 
4096                 /* Go to the next entry */
4097                 NextEntry = NextEntry->Flink;
4098             }
4099 
4100             /* Lower the IRQL */
4101             KeLowerIrql(OldIrql);
4102         }
4103     }
4104 
4105     /* Enter SEH for writing back the I/O Status */
4106     _SEH2_TRY
4107     {
4108         /* Write success */
4109         IoStatusBlock->Status = STATUS_SUCCESS;
4110         IoStatusBlock->Information = 0;
4111     }
4112     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4113     {
4114         /* Ignore exception */
4115     }
4116     _SEH2_END;
4117 
4118     /* Dereference the file object and return success */
4119     ObDereferenceObject(FileObject);
4120     return STATUS_SUCCESS;
4121 }
4122 
4123 /*
4124  * @implemented
4125  */
4126 NTSTATUS
4127 NTAPI
4128 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
4129 {
4130     NTSTATUS Status;
4131     DUMMY_FILE_OBJECT LocalFileObject;
4132     HANDLE Handle;
4133     KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
4134     OPEN_PACKET OpenPacket;
4135     PAGED_CODE();
4136     IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
4137 
4138     /* Setup the Open Packet */
4139     RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
4140     OpenPacket.Type = IO_TYPE_OPEN_PACKET;
4141     OpenPacket.Size = sizeof(OPEN_PACKET);
4142     OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
4143     OpenPacket.ShareAccess = FILE_SHARE_READ |
4144                              FILE_SHARE_WRITE |
4145                              FILE_SHARE_DELETE;
4146     OpenPacket.Disposition = FILE_OPEN;
4147     OpenPacket.DeleteOnly = TRUE;
4148     OpenPacket.LocalFileObject = &LocalFileObject;
4149 
4150     /* Update the operation counts */
4151     IopUpdateOperationCount(IopOtherTransfer);
4152 
4153     /*
4154      * Attempt opening the file. This will call the I/O Parse Routine for
4155      * the File Object (IopParseDevice) which will use the dummy file obejct
4156      * send the IRP to its device object. Note that we have two statuses
4157      * to worry about: the Object Manager's status (in Status) and the I/O
4158      * status, which is in the Open Packet's Final Status, and determined
4159      * by the Parse Check member.
4160      */
4161     Status = ObOpenObjectByName(ObjectAttributes,
4162                                 NULL,
4163                                 AccessMode,
4164                                 NULL,
4165                                 DELETE,
4166                                 &OpenPacket,
4167                                 &Handle);
4168     if (OpenPacket.ParseCheck == FALSE) return Status;
4169 
4170     /* Retrn the Io status */
4171     return OpenPacket.FinalStatus;
4172 }
4173 
4174 /* EOF */
4175