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