[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / io / iomgr / file.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/io/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 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <debug.h>
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 VOID
21 NTAPI
22 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,
23 IN OUT PULONG CreateOptions,
24 IN KPROCESSOR_MODE PreviousMode,
25 IN ULONG Disposition)
26 {
27 ACCESS_MASK DesiredAccess, ReadAccess, WriteAccess;
28 PRIVILEGE_SET Privileges;
29 BOOLEAN AccessGranted, HaveBackupPriv = FALSE, CheckRestore = FALSE;
30 PAGED_CODE();
31
32 /* Don't do anything if privileges were checked already */
33 if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) return;
34
35 /* Check if the file was actually opened for backup purposes */
36 if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
37 {
38 /* Set the check flag since were doing it now */
39 AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
40
41 /* Set the access masks required */
42 ReadAccess = READ_CONTROL |
43 ACCESS_SYSTEM_SECURITY |
44 FILE_GENERIC_READ |
45 FILE_TRAVERSE;
46 WriteAccess = WRITE_DAC |
47 WRITE_OWNER |
48 ACCESS_SYSTEM_SECURITY |
49 FILE_GENERIC_WRITE |
50 FILE_ADD_FILE |
51 FILE_ADD_SUBDIRECTORY |
52 DELETE;
53 DesiredAccess = AccessState->RemainingDesiredAccess;
54
55 /* Check if desired access was the maximum */
56 if (DesiredAccess & MAXIMUM_ALLOWED)
57 {
58 /* Then add all the access masks required */
59 DesiredAccess |= (ReadAccess | WriteAccess);
60 }
61
62 /* Check if the file already exists */
63 if (Disposition & FILE_OPEN)
64 {
65 /* Check if desired access has the read mask */
66 if (ReadAccess & DesiredAccess)
67 {
68 /* Setup the privilege check lookup */
69 Privileges.PrivilegeCount = 1;
70 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
71 Privileges.Privilege[0].Luid = SeBackupPrivilege;
72 Privileges.Privilege[0].Attributes = 0;
73 AccessGranted = SePrivilegeCheck(&Privileges,
74 &AccessState->
75 SubjectSecurityContext,
76 PreviousMode);
77 if (AccessGranted)
78 {
79 /* Remember that backup was allowed */
80 HaveBackupPriv = TRUE;
81
82 /* Append the privileges and update the access state */
83 SeAppendPrivileges(AccessState, &Privileges);
84 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & ReadAccess);
85 AccessState->RemainingDesiredAccess &= ~ReadAccess;
86 DesiredAccess &= ~ReadAccess;
87
88 /* Set backup privilege for the token */
89 AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
90 }
91 }
92 }
93 else
94 {
95 /* Caller is creating the file, check restore privileges later */
96 CheckRestore = TRUE;
97 }
98
99 /* Check if caller wants write access or if it's creating a file */
100 if ((WriteAccess & DesiredAccess) || (CheckRestore))
101 {
102 /* Setup the privilege lookup and do it */
103 Privileges.PrivilegeCount = 1;
104 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
105 Privileges.Privilege[0].Luid = SeRestorePrivilege;
106 Privileges.Privilege[0].Attributes = 0;
107 AccessGranted = SePrivilegeCheck(&Privileges,
108 &AccessState->SubjectSecurityContext,
109 PreviousMode);
110 if (AccessGranted)
111 {
112 /* Remember that privilege was given */
113 HaveBackupPriv = TRUE;
114
115 /* Append the privileges and update the access state */
116 SeAppendPrivileges(AccessState, &Privileges);
117 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & WriteAccess);
118 AccessState->RemainingDesiredAccess &= ~WriteAccess;
119
120 /* Set restore privilege for the token */
121 AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
122 }
123 }
124
125 /* If we don't have the privilege, remove the option */
126 if (!HaveBackupPriv) *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
127 }
128 }
129
130 NTSTATUS
131 NTAPI
132 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
133 IN PDEVICE_OBJECT DeviceObject)
134 {
135 /* Make sure the object is valid */
136 if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
137 (DOE_UNLOAD_PENDING |
138 DOE_DELETE_PENDING |
139 DOE_REMOVE_PENDING |
140 DOE_REMOVE_PROCESSED)) ||
141 (DeviceObject->Flags & DO_DEVICE_INITIALIZING))
142 {
143 /* It's unloading or initializing, so fail */
144 DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
145 " sucks. Please fix it's AddDevice Routine\n",
146 &DeviceObject->DriverObject->DriverName);
147 return STATUS_NO_SUCH_DEVICE;
148 }
149 else if ((DeviceObject->Flags & DO_EXCLUSIVE) &&
150 (DeviceObject->ReferenceCount) &&
151 !(OpenPacket->RelatedFileObject) &&
152 !(OpenPacket->Options & IO_ATTACH_DEVICE))
153 {
154 return STATUS_ACCESS_DENIED;
155 }
156
157 else
158 {
159 /* Increase reference count */
160 InterlockedIncrement(&DeviceObject->ReferenceCount);
161 return STATUS_SUCCESS;
162 }
163 }
164
165 NTSTATUS
166 NTAPI
167 IopParseDevice(IN PVOID ParseObject,
168 IN PVOID ObjectType,
169 IN OUT PACCESS_STATE AccessState,
170 IN KPROCESSOR_MODE AccessMode,
171 IN ULONG Attributes,
172 IN OUT PUNICODE_STRING CompleteName,
173 IN OUT PUNICODE_STRING RemainingName,
174 IN OUT PVOID Context,
175 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
176 OUT PVOID *Object)
177 {
178 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
179 PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
180 PDEVICE_OBJECT DeviceObject, OwnerDevice;
181 NTSTATUS Status;
182 PFILE_OBJECT FileObject;
183 PVPB Vpb = NULL;
184 PIRP Irp;
185 PEXTENDED_IO_STACK_LOCATION StackLoc;
186 IO_SECURITY_CONTEXT SecurityContext;
187 IO_STATUS_BLOCK IoStatusBlock;
188 BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
189 OBJECT_ATTRIBUTES ObjectAttributes;
190 KIRQL OldIrql;
191 PDUMMY_FILE_OBJECT LocalFileObject;
192 PFILE_BASIC_INFORMATION FileBasicInfo;
193 ULONG ReturnLength;
194 KPROCESSOR_MODE CheckMode;
195 BOOLEAN VolumeOpen = FALSE;
196 ACCESS_MASK DesiredAccess, GrantedAccess;
197 BOOLEAN AccessGranted, LockHeld = FALSE;
198 PPRIVILEGE_SET Privileges = NULL;
199 UNICODE_STRING FileString;
200 IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
201 ParseObject, RemainingName);
202
203 /* Assume failure */
204 *Object = NULL;
205
206 /* Validate the open packet */
207 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
208
209 /* Check if we have a related file object */
210 if (OpenPacket->RelatedFileObject)
211 {
212 /* Use the related file object's device object */
213 OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
214 }
215
216 /* Validate device status */
217 Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
218 if (!NT_SUCCESS(Status))
219 {
220 /* We failed, return status */
221 OpenPacket->FinalStatus = Status;
222 return Status;
223 }
224
225 /* Map the generic mask and set the new mapping in the access state */
226 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
227 &IoFileObjectType->TypeInfo.GenericMapping);
228 RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
229 &IoFileObjectType->TypeInfo.GenericMapping);
230 SeSetAccessStateGenericMapping(AccessState,
231 &IoFileObjectType->TypeInfo.GenericMapping);
232 DesiredAccess = AccessState->RemainingDesiredAccess;
233
234 /* Check what kind of access checks to do */
235 if ((AccessMode != KernelMode) ||
236 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
237 {
238 /* Call is from user-mode or kernel is forcing checks */
239 CheckMode = UserMode;
240 }
241 else
242 {
243 /* Call is from the kernel */
244 CheckMode = KernelMode;
245 }
246
247 /* Check privilege for backup or restore operation */
248 IopCheckBackupRestorePrivilege(AccessState,
249 &OpenPacket->CreateOptions,
250 CheckMode,
251 OpenPacket->Disposition);
252
253 /* Check if we are re-parsing */
254 if (((OpenPacket->Override) && !(RemainingName->Length)) ||
255 (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
256 {
257 /* Get granted access from the last call */
258 DesiredAccess |= AccessState->PreviouslyGrantedAccess;
259 }
260
261 /* Check if this is a volume open */
262 if ((OpenPacket->RelatedFileObject) &&
263 (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
264 !(RemainingName->Length))
265 {
266 /* It is */
267 VolumeOpen = TRUE;
268 }
269
270 /* Now check if we need access checks */
271 if (((AccessMode != KernelMode) ||
272 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
273 (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
274 !(OpenPacket->Override))
275 {
276 /* Check if a device object is being parsed */
277 if (!RemainingName->Length)
278 {
279 /* Lock the subject context */
280 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
281 LockHeld = TRUE;
282
283 /* Do access check */
284 AccessGranted = SeAccessCheck(OriginalDeviceObject->
285 SecurityDescriptor,
286 &AccessState->SubjectSecurityContext,
287 LockHeld,
288 DesiredAccess,
289 0,
290 &Privileges,
291 &IoFileObjectType->
292 TypeInfo.GenericMapping,
293 UserMode,
294 &GrantedAccess,
295 &Status);
296 if (Privileges)
297 {
298 /* Append and free the privileges */
299 SeAppendPrivileges(AccessState, Privileges);
300 SeFreePrivileges(Privileges);
301 }
302
303 /* Check if we got access */
304 if (AccessGranted)
305 {
306 /* Update access state */
307 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
308 AccessState->RemainingDesiredAccess &= ~(GrantedAccess &
309 MAXIMUM_ALLOWED);
310 OpenPacket->Override= TRUE;
311 }
312
313 FileString.Length = 8;
314 FileString.MaximumLength = 8;
315 FileString.Buffer = L"File";
316
317 /* Do Audit/Alarm for open operation */
318 SeOpenObjectAuditAlarm(&FileString,
319 OriginalDeviceObject,
320 CompleteName,
321 OriginalDeviceObject->SecurityDescriptor,
322 AccessState,
323 FALSE,
324 AccessGranted,
325 UserMode,
326 &AccessState->GenerateOnClose);
327 }
328 else
329 {
330 /* Check if we need to do traverse validation */
331 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
332 ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
333 (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
334 {
335 /* Check if this is a restricted token */
336 if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
337 {
338 /* Do the FAST traverse check */
339 AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
340 AccessState,
341 FILE_TRAVERSE,
342 UserMode);
343 }
344 else
345 {
346 /* Fail */
347 AccessGranted = FALSE;
348 }
349
350 /* Check if we failed to get access */
351 if (!AccessGranted)
352 {
353 /* Lock the subject context */
354 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
355 LockHeld = TRUE;
356
357 /* Do access check */
358 AccessGranted = SeAccessCheck(OriginalDeviceObject->
359 SecurityDescriptor,
360 &AccessState->SubjectSecurityContext,
361 LockHeld,
362 FILE_TRAVERSE,
363 0,
364 &Privileges,
365 &IoFileObjectType->
366 TypeInfo.GenericMapping,
367 UserMode,
368 &GrantedAccess,
369 &Status);
370 if (Privileges)
371 {
372 /* Append and free the privileges */
373 SeAppendPrivileges(AccessState, Privileges);
374 SeFreePrivileges(Privileges);
375 }
376 }
377
378 /* FIXME: Do Audit/Alarm for traverse check */
379 }
380 else
381 {
382 /* Access automatically granted */
383 AccessGranted = TRUE;
384 }
385 }
386
387 /* Check if we hold the lock */
388 if (LockHeld)
389 {
390 /* Release it */
391 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
392 }
393
394 /* Check if access failed */
395 if (!AccessGranted)
396 {
397 /* Dereference the device and fail */
398 DPRINT1("Traverse access failed!\n");
399 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
400 return STATUS_ACCESS_DENIED;
401 }
402 }
403
404 /* Check if we can simply use a dummy file */
405 UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
406
407 /* Check if this is a direct open */
408 if (!(RemainingName->Length) &&
409 !(OpenPacket->RelatedFileObject) &&
410 ((DesiredAccess & ~(SYNCHRONIZE |
411 FILE_READ_ATTRIBUTES |
412 READ_CONTROL |
413 ACCESS_SYSTEM_SECURITY |
414 WRITE_OWNER |
415 WRITE_DAC)) == 0) &&
416 !(UseDummyFile))
417 {
418 /* Remember this for later */
419 DirectOpen = TRUE;
420 }
421
422 #if 0
423 /* FIXME: Small hack still exists, have to check why...
424 * This is triggered multiple times by usetup and then once per boot.
425 */
426 if (!(DirectOpen) &&
427 !(RemainingName->Length) &&
428 !(OpenPacket->RelatedFileObject) &&
429 ((wcsstr(CompleteName->Buffer, L"Harddisk")) ||
430 (wcsstr(CompleteName->Buffer, L"Floppy"))) &&
431 !(UseDummyFile))
432 {
433 DPRINT1("Using IopParseDevice() hack. Requested invalid attributes: %lx\n",
434 DesiredAccess & ~(SYNCHRONIZE |
435 FILE_READ_ATTRIBUTES |
436 READ_CONTROL |
437 ACCESS_SYSTEM_SECURITY |
438 WRITE_OWNER |
439 WRITE_DAC));
440 DirectOpen = TRUE;
441 }
442 #endif
443
444 /* Check if we have a related FO that wasn't a direct open */
445 if ((OpenPacket->RelatedFileObject) &&
446 !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
447 {
448 /* The device object is the one we were given */
449 DeviceObject = ParseObject;
450
451 /* Check if the related FO had a VPB */
452 if (OpenPacket->RelatedFileObject->Vpb)
453 {
454 /* Yes, remember it */
455 Vpb = OpenPacket->RelatedFileObject->Vpb;
456
457 /* Reference it */
458 InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
459 }
460 }
461 else
462 {
463 /* The device object is the one we were given */
464 DeviceObject = OriginalDeviceObject;
465
466 /* Check if it has a VPB */
467 if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
468 {
469 /* Check if the VPB is mounted, and mount it */
470 Vpb = IopCheckVpbMounted(OpenPacket,
471 OriginalDeviceObject,
472 RemainingName,
473 &Status);
474 if (!Vpb) return Status;
475
476 /* Get the VPB's device object */
477 DeviceObject = Vpb->DeviceObject;
478 }
479
480 /* Check if there's an attached device */
481 if (DeviceObject->AttachedDevice)
482 {
483 /* Get the attached device */
484 DeviceObject = IoGetAttachedDevice(DeviceObject);
485 }
486 }
487
488 /* Check if this is a secure FSD */
489 if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
490 ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
491 (!VolumeOpen))
492 {
493 DPRINT("Fix Secure FSD support!!!\n");
494 }
495
496 /* Allocate the IRP */
497 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
498 if (!Irp)
499 {
500 /* Dereference the device and VPB, then fail */
501 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
502 if (Vpb) IopDereferenceVpbAndFree(Vpb);
503 return STATUS_INSUFFICIENT_RESOURCES;
504 }
505
506 /* Now set the IRP data */
507 Irp->RequestorMode = AccessMode;
508 Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
509 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
510 Irp->UserIosb = &IoStatusBlock;
511 Irp->MdlAddress = NULL;
512 Irp->PendingReturned = FALSE;
513 Irp->UserEvent = NULL;
514 Irp->Cancel = FALSE;
515 Irp->CancelRoutine = NULL;
516 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
517
518 /* Setup the security context */
519 SecurityContext.SecurityQos = SecurityQos;
520 SecurityContext.AccessState = AccessState;
521 SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
522 SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
523
524 /* Get the I/O Stack location */
525 StackLoc = (PEXTENDED_IO_STACK_LOCATION)IoGetNextIrpStackLocation(Irp);
526 StackLoc->Control = 0;
527
528 /* Check what kind of file this is */
529 switch (OpenPacket->CreateFileType)
530 {
531 /* Normal file */
532 case CreateFileTypeNone:
533
534 /* Set the major function and EA Length */
535 StackLoc->MajorFunction = IRP_MJ_CREATE;
536 StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
537
538 /* Set the flags */
539 StackLoc->Flags = (UCHAR)OpenPacket->Options;
540 StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
541 break;
542
543 /* Named pipe */
544 case CreateFileTypeNamedPipe:
545
546 /* Set the named pipe MJ and set the parameters */
547 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
548 StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
549 break;
550
551 /* Mailslot */
552 case CreateFileTypeMailslot:
553
554 /* Set the mailslot MJ and set the parameters */
555 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
556 StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
557 break;
558 }
559
560 /* Set the common data */
561 Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
562 Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
563 StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
564 (OpenPacket->CreateOptions &
565 0xFFFFFF);
566 StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
567 StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
568 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
569
570 /* Check if we really need to create an object */
571 if (!UseDummyFile)
572 {
573 /* Create the actual file object */
574 InitializeObjectAttributes(&ObjectAttributes,
575 NULL,
576 Attributes,
577 NULL,
578 NULL);
579 Status = ObCreateObject(KernelMode,
580 IoFileObjectType,
581 &ObjectAttributes,
582 AccessMode,
583 NULL,
584 sizeof(FILE_OBJECT),
585 0,
586 0,
587 (PVOID*)&FileObject);
588 if (!NT_SUCCESS(Status))
589 {
590 /* Create failed, free the IRP */
591 IoFreeIrp(Irp);
592
593 /* Dereference the device and VPB */
594 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
595 if (Vpb) IopDereferenceVpbAndFree(Vpb);
596
597 /* We failed, return status */
598 OpenPacket->FinalStatus = Status;
599 return Status;
600 }
601
602 /* Clear the file object */
603 RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
604
605 /* Check if this is Synch I/O */
606 if (OpenPacket->CreateOptions &
607 (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
608 {
609 /* Set the synch flag */
610 FileObject->Flags |= FO_SYNCHRONOUS_IO;
611
612 /* Check if it's also alertable */
613 if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
614 {
615 /* It is, set the alertable flag */
616 FileObject->Flags |= FO_ALERTABLE_IO;
617 }
618 }
619
620 /* Check if this is synch I/O */
621 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
622 {
623 /* Initialize the event */
624 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
625 }
626
627 /* Check if the caller requested no intermediate buffering */
628 if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
629 {
630 /* Set the correct flag for the FSD to read */
631 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
632 }
633
634 /* Check if the caller requested write through support */
635 if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
636 {
637 /* Set the correct flag for the FSD to read */
638 FileObject->Flags |= FO_WRITE_THROUGH;
639 }
640
641 /* Check if the caller says the file will be only read sequentially */
642 if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
643 {
644 /* Set the correct flag for the FSD to read */
645 FileObject->Flags |= FO_SEQUENTIAL_ONLY;
646 }
647
648 /* Check if the caller believes the file will be only read randomly */
649 if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
650 {
651 /* Set the correct flag for the FSD to read */
652 FileObject->Flags |= FO_RANDOM_ACCESS;
653 }
654 }
655 else
656 {
657 /* Use the dummy object instead */
658 LocalFileObject = OpenPacket->LocalFileObject;
659 RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
660
661 /* Set it up */
662 FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
663 LocalFileObject->ObjectHeader.Type = IoFileObjectType;
664 LocalFileObject->ObjectHeader.PointerCount = 1;
665 }
666
667 /* Setup the file header */
668 FileObject->Type = IO_TYPE_FILE;
669 FileObject->Size = sizeof(FILE_OBJECT);
670 FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
671 FileObject->DeviceObject = OriginalDeviceObject;
672
673 /* Check if this is a direct device open */
674 if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
675
676 /* Check if the caller wants case sensitivity */
677 if (!(Attributes & OBJ_CASE_INSENSITIVE))
678 {
679 /* Tell the driver about it */
680 FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
681 }
682
683 /* Now set the file object */
684 Irp->Tail.Overlay.OriginalFileObject = FileObject;
685 StackLoc->FileObject = FileObject;
686
687 /* Check if the file object has a name */
688 if (RemainingName->Length)
689 {
690 /* Setup the unicode string */
691 FileObject->FileName.MaximumLength = RemainingName->Length +
692 sizeof(WCHAR);
693 FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
694 FileObject->
695 FileName.
696 MaximumLength,
697 TAG_IO_NAME);
698 if (!FileObject->FileName.Buffer)
699 {
700 /* Failed to allocate the name, free the IRP */
701 IoFreeIrp(Irp);
702
703 /* Dereference the device object and VPB */
704 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
705 if (Vpb) IopDereferenceVpbAndFree(Vpb);
706
707 /* Clear the FO and dereference it */
708 FileObject->DeviceObject = NULL;
709 if (!UseDummyFile) ObDereferenceObject(FileObject);
710
711 /* Fail */
712 return STATUS_INSUFFICIENT_RESOURCES;
713 }
714 }
715
716 /* Copy the name */
717 RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
718
719 /* Initialize the File Object event and set the FO */
720 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
721 OpenPacket->FileObject = FileObject;
722
723 /* Queue the IRP and call the driver */
724 IopQueueIrpToThread(Irp);
725 Status = IoCallDriver(DeviceObject, Irp);
726 if (Status == STATUS_PENDING)
727 {
728 /* Wait for the driver to complete the create */
729 KeWaitForSingleObject(&FileObject->Event,
730 Executive,
731 KernelMode,
732 FALSE,
733 NULL);
734
735 /* Get the new status */
736 Status = IoStatusBlock.Status;
737 }
738 else
739 {
740 /* We'll have to complete it ourselves */
741 ASSERT(!Irp->PendingReturned);
742 ASSERT(!Irp->MdlAddress);
743
744 /* Completion happens at APC_LEVEL */
745 KeRaiseIrql(APC_LEVEL, &OldIrql);
746
747 /* Get the new I/O Status block ourselves */
748 IoStatusBlock = Irp->IoStatus;
749 Status = IoStatusBlock.Status;
750
751 /* Manually signal the even, we can't have any waiters */
752 FileObject->Event.Header.SignalState = 1;
753
754 /* Now that we've signaled the events, de-associate the IRP */
755 IopUnQueueIrpFromThread(Irp);
756
757 /* Check if the IRP had an input buffer */
758 if ((Irp->Flags & IRP_BUFFERED_IO) &&
759 (Irp->Flags & IRP_DEALLOCATE_BUFFER))
760 {
761 /* Free it. A driver might've tacked one on */
762 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
763 }
764
765 /* Free the IRP and bring the IRQL back down */
766 IoFreeIrp(Irp);
767 KeLowerIrql(OldIrql);
768 }
769
770 /* Copy the I/O Status */
771 OpenPacket->Information = IoStatusBlock.Information;
772
773 /* The driver failed to create the file */
774 if (!NT_SUCCESS(Status))
775 {
776 /* Check if we have a name */
777 if (FileObject->FileName.Length)
778 {
779 /* Free it */
780 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
781 FileObject->FileName.Length = 0;
782 }
783
784 /* Clear its device object */
785 FileObject->DeviceObject = NULL;
786
787 /* Save this now because the FO might go away */
788 OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
789 TRUE : FALSE;
790
791 /* Clear the file object in the open packet */
792 OpenPacket->FileObject = NULL;
793
794 /* Dereference the file object */
795 if (!UseDummyFile) ObDereferenceObject(FileObject);
796
797 /* Dereference the device object */
798 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
799
800 /* Unless the driver cancelled the open, dereference the VPB */
801 if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
802
803 /* Set the status and return */
804 OpenPacket->FinalStatus = Status;
805 return Status;
806 }
807 else if (Status == STATUS_REPARSE)
808 {
809 /* FIXME: We don't handle this at all! */
810 ASSERT(FALSE);
811 }
812
813 /* Get the owner of the File Object */
814 OwnerDevice = IoGetRelatedDeviceObject(FileObject);
815
816 /*
817 * It's possible that the device to whom we sent the IRP to
818 * isn't actually the device that ended opening the file object
819 * internally.
820 */
821 if (OwnerDevice != DeviceObject)
822 {
823 /* We have to de-reference the VPB we had associated */
824 if (Vpb) IopDereferenceVpbAndFree(Vpb);
825
826 /* And re-associate with the actual one */
827 Vpb = FileObject->Vpb;
828 if (Vpb) InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
829 }
830
831 /* Make sure we are not using a dummy */
832 if (!UseDummyFile)
833 {
834 /* Check if this was a volume open */
835 if ((!(FileObject->RelatedFileObject) ||
836 (FileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN)) &&
837 !(FileObject->FileName.Length))
838 {
839 /* All signs point to it, but make sure it was actually an FSD */
840 if ((OwnerDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
841 (OwnerDevice->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
842 (OwnerDevice->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) ||
843 (OwnerDevice->DeviceType == FILE_DEVICE_FILE_SYSTEM))
844 {
845 /* The owner device is an FSD, so this is a volume open for real */
846 FileObject->Flags |= FO_VOLUME_OPEN;
847 }
848 }
849
850 /* Reference the object and set the parse check */
851 ObReferenceObject(FileObject);
852 *Object = FileObject;
853 OpenPacket->FinalStatus = IoStatusBlock.Status;
854 OpenPacket->ParseCheck = TRUE;
855 return OpenPacket->FinalStatus;
856 }
857 else
858 {
859 /* Check if this was a query */
860 if (OpenPacket->QueryOnly)
861 {
862 /* Check if the caller wants basic info only */
863 if (!OpenPacket->FullAttributes)
864 {
865 /* Allocate the buffer */
866 FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
867 sizeof(*FileBasicInfo),
868 TAG_IO);
869 if (FileBasicInfo)
870 {
871 /* Do the query */
872 Status = IoQueryFileInformation(FileObject,
873 FileBasicInformation,
874 sizeof(*FileBasicInfo),
875 FileBasicInfo,
876 &ReturnLength);
877 if (NT_SUCCESS(Status))
878 {
879 /* Copy the data */
880 RtlCopyMemory(OpenPacket->BasicInformation,
881 FileBasicInfo,
882 ReturnLength);
883 }
884
885 /* Free our buffer */
886 ExFreePoolWithTag(FileBasicInfo, TAG_IO);
887 }
888 else
889 {
890 /* Fail */
891 Status = STATUS_INSUFFICIENT_RESOURCES;
892 }
893 }
894 else
895 {
896 /* This is a full query */
897 Status = IoQueryFileInformation(
898 FileObject,
899 FileNetworkOpenInformation,
900 sizeof(FILE_NETWORK_OPEN_INFORMATION),
901 OpenPacket->NetworkInformation,
902 &ReturnLength);
903 if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
904 }
905 }
906
907 /* Delete the file object */
908 IopDeleteFile(FileObject);
909
910 /* Clear out the file */
911 OpenPacket->FileObject = NULL;
912
913 /* Set and return status */
914 OpenPacket->FinalStatus = Status;
915 OpenPacket->ParseCheck = TRUE;
916 return Status;
917 }
918 }
919
920 NTSTATUS
921 NTAPI
922 IopParseFile(IN PVOID ParseObject,
923 IN PVOID ObjectType,
924 IN OUT PACCESS_STATE AccessState,
925 IN KPROCESSOR_MODE AccessMode,
926 IN ULONG Attributes,
927 IN OUT PUNICODE_STRING CompleteName,
928 IN OUT PUNICODE_STRING RemainingName,
929 IN OUT PVOID Context OPTIONAL,
930 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
931 OUT PVOID *Object)
932 {
933 PVOID DeviceObject;
934 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
935
936 /* Validate the open packet */
937 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
938
939 /* Get the device object */
940 DeviceObject = IoGetRelatedDeviceObject(ParseObject);
941 OpenPacket->RelatedFileObject = ParseObject;
942
943 /* Call the main routine */
944 return IopParseDevice(DeviceObject,
945 ObjectType,
946 AccessState,
947 AccessMode,
948 Attributes,
949 CompleteName,
950 RemainingName,
951 OpenPacket,
952 SecurityQos,
953 Object);
954 }
955
956 VOID
957 NTAPI
958 IopDeleteFile(IN PVOID ObjectBody)
959 {
960 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
961 PIRP Irp;
962 PIO_STACK_LOCATION StackPtr;
963 NTSTATUS Status;
964 KEVENT Event;
965 PDEVICE_OBJECT DeviceObject;
966 BOOLEAN DereferenceDone = FALSE;
967 PVPB Vpb;
968 KIRQL OldIrql;
969 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
970
971 /* Check if the file has a device object */
972 if (FileObject->DeviceObject)
973 {
974 /* Check if this is a direct open or not */
975 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
976 {
977 /* Get the attached device */
978 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
979 }
980 else
981 {
982 /* Use the file object's device object */
983 DeviceObject = IoGetRelatedDeviceObject(FileObject);
984 }
985
986 /* Sanity check */
987 ASSERT(!(FileObject->Flags & FO_SYNCHRONOUS_IO) ||
988 (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE));
989
990 /* Check if the handle wasn't created yet */
991 if (!(FileObject->Flags & FO_HANDLE_CREATED))
992 {
993 /* Send the cleanup IRP */
994 IopCloseFile(NULL, ObjectBody, 0, 1, 1);
995 }
996
997 /* Clear and set up Events */
998 KeClearEvent(&FileObject->Event);
999 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1000
1001 /* Allocate an IRP */
1002 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1003 if (!Irp) return;
1004
1005 /* Set it up */
1006 Irp->UserEvent = &Event;
1007 Irp->UserIosb = &Irp->IoStatus;
1008 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1009 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1010 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1011
1012 /* Set up Stack Pointer Data */
1013 StackPtr = IoGetNextIrpStackLocation(Irp);
1014 StackPtr->MajorFunction = IRP_MJ_CLOSE;
1015 StackPtr->FileObject = FileObject;
1016
1017 /* Queue the IRP */
1018 IopQueueIrpToThread(Irp);
1019
1020 /* Get the VPB and check if this isn't a direct open */
1021 Vpb = FileObject->Vpb;
1022 if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1023 {
1024 /* Dereference the VPB before the close */
1025 InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
1026 }
1027
1028 /* Check if the FS will never disappear by itself */
1029 if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
1030 {
1031 /* Dereference it */
1032 InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
1033 DereferenceDone = TRUE;
1034 }
1035
1036 /* Call the FS Driver */
1037 Status = IoCallDriver(DeviceObject, Irp);
1038 if (Status == STATUS_PENDING)
1039 {
1040 /* Wait for completion */
1041 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1042 }
1043
1044 /* De-queue the IRP */
1045 KeRaiseIrql(APC_LEVEL, &OldIrql);
1046 IopUnQueueIrpFromThread(Irp);
1047 KeLowerIrql(OldIrql);
1048
1049 /* Free the IRP */
1050 IoFreeIrp(Irp);
1051
1052 /* Clear the file name */
1053 if (FileObject->FileName.Buffer)
1054 {
1055 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1056 FileObject->FileName.Buffer = NULL;
1057 }
1058
1059 /* Check if the FO had a completion port */
1060 if (FileObject->CompletionContext)
1061 {
1062 /* Free it */
1063 ObDereferenceObject(FileObject->CompletionContext->Port);
1064 ExFreePool(FileObject->CompletionContext);
1065 }
1066
1067 /* Check if the FO had extension */
1068 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1069 {
1070 /* Release filter context structure if any */
1071 FsRtlPTeardownPerFileObjectContexts(FileObject);
1072 }
1073
1074 /* Check if dereference has been done yet */
1075 if (!DereferenceDone)
1076 {
1077 /* Dereference device object */
1078 IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
1079 }
1080 }
1081 }
1082
1083 NTSTATUS
1084 NTAPI
1085 IopSecurityFile(IN PVOID ObjectBody,
1086 IN SECURITY_OPERATION_CODE OperationCode,
1087 IN PSECURITY_INFORMATION SecurityInformation,
1088 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1089 IN OUT PULONG BufferLength,
1090 IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
1091 IN POOL_TYPE PoolType,
1092 IN OUT PGENERIC_MAPPING GenericMapping)
1093 {
1094 IO_STATUS_BLOCK IoStatusBlock;
1095 PIO_STACK_LOCATION StackPtr;
1096 PFILE_OBJECT FileObject;
1097 PDEVICE_OBJECT DeviceObject;
1098 PIRP Irp;
1099 BOOLEAN LocalEvent = FALSE;
1100 KEVENT Event;
1101 NTSTATUS Status = STATUS_SUCCESS;
1102 PAGED_CODE();
1103 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1104
1105 /* Check if this is a device or file */
1106 if (((PFILE_OBJECT)ObjectBody)->Type == IO_TYPE_DEVICE)
1107 {
1108 /* It's a device */
1109 DeviceObject = (PDEVICE_OBJECT)ObjectBody;
1110 FileObject = NULL;
1111 }
1112 else
1113 {
1114 /* It's a file */
1115 FileObject = (PFILE_OBJECT)ObjectBody;
1116
1117 /* Check if this is a direct open */
1118 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1119 {
1120 /* Get the Device Object */
1121 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1122 }
1123 else
1124 {
1125 /* Otherwise, use the direct device*/
1126 DeviceObject = FileObject->DeviceObject;
1127 }
1128 }
1129
1130 /* Check if the request was for a device object */
1131 if (!(FileObject) ||
1132 (!(FileObject->FileName.Length) && !(FileObject->RelatedFileObject)) ||
1133 (FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1134 {
1135 /* Check what kind of request this was */
1136 if (OperationCode == QuerySecurityDescriptor)
1137 {
1138 return SeQuerySecurityDescriptorInfo(SecurityInformation,
1139 SecurityDescriptor,
1140 BufferLength,
1141 &DeviceObject->SecurityDescriptor);
1142 }
1143 else if (OperationCode == DeleteSecurityDescriptor)
1144 {
1145 /* Simply return success */
1146 return STATUS_SUCCESS;
1147 }
1148 else if (OperationCode == AssignSecurityDescriptor)
1149 {
1150 /* Make absolutely sure this is a device object */
1151 if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
1152 {
1153 /* Assign the Security Descriptor */
1154 DeviceObject->SecurityDescriptor = SecurityDescriptor;
1155 }
1156
1157 /* Return success */
1158 return STATUS_SUCCESS;
1159 }
1160 else
1161 {
1162 DPRINT1("FIXME: Set SD unimplemented for Devices\n");
1163 return STATUS_SUCCESS;
1164 }
1165 }
1166 else if (OperationCode == DeleteSecurityDescriptor)
1167 {
1168 /* Same as for devices, do nothing */
1169 return STATUS_SUCCESS;
1170 }
1171
1172 /* At this point, we know we're a file. Reference it */
1173 ObReferenceObject(FileObject);
1174
1175 /* Check if we should use Sync IO or not */
1176 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1177 {
1178 /* Lock the file object */
1179 IopLockFileObject(FileObject);
1180 }
1181 else
1182 {
1183 /* Use local event */
1184 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1185 LocalEvent = TRUE;
1186 }
1187
1188 /* Clear the File Object event */
1189 KeClearEvent(&FileObject->Event);
1190
1191 /* Get the device object */
1192 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1193
1194 /* Allocate the IRP */
1195 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1196 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1197
1198 /* Set the IRP */
1199 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1200 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1201 Irp->RequestorMode = ExGetPreviousMode();
1202 Irp->UserIosb = &IoStatusBlock;
1203 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1204 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1205 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1206
1207 /* Set Stack Parameters */
1208 StackPtr = IoGetNextIrpStackLocation(Irp);
1209 StackPtr->FileObject = FileObject;
1210
1211 /* Check if this is a query or set */
1212 if (OperationCode == QuerySecurityDescriptor)
1213 {
1214 /* Set the major function and parameters */
1215 StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
1216 StackPtr->Parameters.QuerySecurity.SecurityInformation =
1217 *SecurityInformation;
1218 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
1219 Irp->UserBuffer = SecurityDescriptor;
1220 }
1221 else
1222 {
1223 /* Set the major function and parameters for a set */
1224 StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
1225 StackPtr->Parameters.SetSecurity.SecurityInformation =
1226 *SecurityInformation;
1227 StackPtr->Parameters.SetSecurity.SecurityDescriptor =
1228 SecurityDescriptor;
1229 }
1230
1231 /* Queue the IRP */
1232 IopQueueIrpToThread(Irp);
1233
1234 /* Update operation counts */
1235 IopUpdateOperationCount(IopOtherTransfer);
1236
1237 /* Call the Driver */
1238 Status = IoCallDriver(DeviceObject, Irp);
1239
1240 /* Check if this was async I/O */
1241 if (LocalEvent)
1242 {
1243 /* Check if the IRP is pending completion */
1244 if (Status == STATUS_PENDING)
1245 {
1246 /* Wait on the local event */
1247 KeWaitForSingleObject(&Event,
1248 Executive,
1249 KernelMode,
1250 FALSE,
1251 NULL);
1252 Status = IoStatusBlock.Status;
1253 }
1254 }
1255 else
1256 {
1257 /* Check if the IRP is pending completion */
1258 if (Status == STATUS_PENDING)
1259 {
1260 /* Wait on the file object */
1261 KeWaitForSingleObject(&FileObject->Event,
1262 Executive,
1263 KernelMode,
1264 FALSE,
1265 NULL);
1266 Status = FileObject->FinalStatus;
1267 }
1268
1269 /* Release the lock */
1270 IopUnlockFileObject(FileObject);
1271 }
1272
1273 /* This Driver doesn't implement Security, so try to give it a default */
1274 if (Status == STATUS_INVALID_DEVICE_REQUEST)
1275 {
1276 /* Was this a query? */
1277 if (OperationCode == QuerySecurityDescriptor)
1278 {
1279 /* Set a World Security Descriptor */
1280 Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
1281 SecurityDescriptor,
1282 BufferLength);
1283 }
1284 else
1285 {
1286 /* It wasn't a query, so just fake success */
1287 Status = STATUS_SUCCESS;
1288 }
1289 }
1290 else if (OperationCode == QuerySecurityDescriptor)
1291 {
1292 /* Callers usually expect the normalized form */
1293 if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_BUFFER_TOO_SMALL;
1294
1295 _SEH2_TRY
1296 {
1297 /* Return length */
1298 *BufferLength = (ULONG)IoStatusBlock.Information;
1299 }
1300 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1301 {
1302 /* Get the exception code */
1303 Status = _SEH2_GetExceptionCode();
1304 }
1305 _SEH2_END;
1306 }
1307
1308 /* Return Status */
1309 return Status;
1310 }
1311
1312 NTSTATUS
1313 NTAPI
1314 IopQueryNameFile(IN PVOID ObjectBody,
1315 IN BOOLEAN HasName,
1316 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1317 IN ULONG Length,
1318 OUT PULONG ReturnLength,
1319 IN KPROCESSOR_MODE PreviousMode)
1320 {
1321 POBJECT_NAME_INFORMATION LocalInfo;
1322 PFILE_NAME_INFORMATION LocalFileInfo;
1323 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1324 ULONG LocalReturnLength, FileLength;
1325 BOOLEAN LengthMismatch = FALSE;
1326 NTSTATUS Status;
1327 PWCHAR p;
1328 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1329
1330 /* Validate length */
1331 if (Length < sizeof(OBJECT_NAME_INFORMATION))
1332 {
1333 /* Wrong length, fail */
1334 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1335 return STATUS_INFO_LENGTH_MISMATCH;
1336 }
1337
1338 /* Allocate Buffer */
1339 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1340 if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1341
1342 /* Query the name */
1343 Status = ObQueryNameString(FileObject->DeviceObject,
1344 LocalInfo,
1345 Length,
1346 &LocalReturnLength);
1347 if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
1348 {
1349 /* Free the buffer and fail */
1350 ExFreePoolWithTag(LocalInfo, TAG_IO);
1351 return Status;
1352 }
1353
1354 /* Copy the information */
1355 RtlCopyMemory(ObjectNameInfo,
1356 LocalInfo,
1357 (LocalReturnLength > Length) ?
1358 Length : LocalReturnLength);
1359
1360 /* Set buffer pointer */
1361 p = (PWCHAR)(ObjectNameInfo + 1);
1362 ObjectNameInfo->Name.Buffer = p;
1363
1364 /* Advance in buffer */
1365 p += (LocalInfo->Name.Length / sizeof(WCHAR));
1366
1367 /* Check if this already filled our buffer */
1368 if (LocalReturnLength > Length)
1369 {
1370 /* Set the length mismatch to true, so that we can return
1371 * the proper buffer size to the caller later
1372 */
1373 LengthMismatch = TRUE;
1374
1375 /* Save the initial buffer length value */
1376 *ReturnLength = LocalReturnLength;
1377 }
1378
1379 /* Now get the file name buffer and check the length needed */
1380 LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
1381 FileLength = Length -
1382 LocalReturnLength +
1383 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
1384
1385 /* Query the File name */
1386 Status = IoQueryFileInformation(FileObject,
1387 FileNameInformation,
1388 LengthMismatch ? Length : FileLength,
1389 LocalFileInfo,
1390 &LocalReturnLength);
1391 if (NT_ERROR(Status))
1392 {
1393 /* Fail on errors only, allow warnings */
1394 ExFreePoolWithTag(LocalInfo, TAG_IO);
1395 return Status;
1396 }
1397
1398 /* If the provided buffer is too small, return the required size */
1399 if (LengthMismatch)
1400 {
1401 /* Add the required length */
1402 *ReturnLength += LocalFileInfo->FileNameLength;
1403
1404 /* Free the allocated buffer and return failure */
1405 ExFreePoolWithTag(LocalInfo, TAG_IO);
1406 return STATUS_BUFFER_OVERFLOW;
1407 }
1408
1409 /* Now calculate the new lengths left */
1410 FileLength = LocalReturnLength -
1411 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
1412 LocalReturnLength = (ULONG)((ULONG_PTR)p -
1413 (ULONG_PTR)ObjectNameInfo +
1414 LocalFileInfo->FileNameLength);
1415
1416 /* Write the Name and null-terminate it */
1417 RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
1418 p += (FileLength / sizeof(WCHAR));
1419 *p = UNICODE_NULL;
1420 LocalReturnLength += sizeof(UNICODE_NULL);
1421
1422 /* Return the length needed */
1423 *ReturnLength = LocalReturnLength;
1424
1425 /* Setup the length and maximum length */
1426 FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
1427 ObjectNameInfo->Name.Length = (USHORT)FileLength -
1428 sizeof(OBJECT_NAME_INFORMATION);
1429 ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
1430 sizeof(UNICODE_NULL);
1431
1432 /* Free buffer and return */
1433 ExFreePoolWithTag(LocalInfo, TAG_IO);
1434 return Status;
1435 }
1436
1437 VOID
1438 NTAPI
1439 IopCloseFile(IN PEPROCESS Process OPTIONAL,
1440 IN PVOID ObjectBody,
1441 IN ACCESS_MASK GrantedAccess,
1442 IN ULONG HandleCount,
1443 IN ULONG SystemHandleCount)
1444 {
1445 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1446 KEVENT Event;
1447 PIRP Irp;
1448 PIO_STACK_LOCATION StackPtr;
1449 NTSTATUS Status;
1450 PDEVICE_OBJECT DeviceObject;
1451 KIRQL OldIrql;
1452 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1453
1454 /* If this isn't the last handle for the current process, quit */
1455 if (HandleCount != 1) return;
1456
1457 /* Check if the file is locked and has more then one handle opened */
1458 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
1459 {
1460 DPRINT1("We need to unlock this file!\n");
1461 ASSERT(FALSE);
1462 }
1463
1464 /* Make sure this is the last handle */
1465 if (SystemHandleCount != 1) return;
1466
1467 /* Check if this is a direct open or not */
1468 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1469 {
1470 /* Get the attached device */
1471 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1472 }
1473 else
1474 {
1475 /* Get the FO's device */
1476 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1477 }
1478
1479 /* Set the handle created flag */
1480 FileObject->Flags |= FO_HANDLE_CREATED;
1481
1482 /* Check if this is a sync FO and lock it */
1483 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopLockFileObject(FileObject);
1484
1485 /* Clear and set up Events */
1486 KeClearEvent(&FileObject->Event);
1487 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1488
1489 /* Allocate an IRP */
1490 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1491 if (!Irp) return;
1492
1493 /* Set it up */
1494 Irp->UserEvent = &Event;
1495 Irp->UserIosb = &Irp->IoStatus;
1496 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1497 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1498 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1499 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1500
1501 /* Set up Stack Pointer Data */
1502 StackPtr = IoGetNextIrpStackLocation(Irp);
1503 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
1504 StackPtr->FileObject = FileObject;
1505
1506 /* Queue the IRP */
1507 IopQueueIrpToThread(Irp);
1508
1509 /* Update operation counts */
1510 IopUpdateOperationCount(IopOtherTransfer);
1511
1512 /* Call the FS Driver */
1513 Status = IoCallDriver(DeviceObject, Irp);
1514 if (Status == STATUS_PENDING)
1515 {
1516 /* Wait for completion */
1517 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
1518 }
1519
1520 /* Unqueue the IRP */
1521 KeRaiseIrql(APC_LEVEL, &OldIrql);
1522 IopUnQueueIrpFromThread(Irp);
1523 KeLowerIrql(OldIrql);
1524
1525 /* Free the IRP */
1526 IoFreeIrp(Irp);
1527
1528 /* Release the lock if we were holding it */
1529 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
1530 }
1531
1532 NTSTATUS
1533 NTAPI
1534 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
1535 IN FILE_INFORMATION_CLASS FileInformationClass,
1536 IN ULONG FileInformationSize,
1537 OUT PVOID FileInformation)
1538 {
1539 NTSTATUS Status;
1540 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
1541 DUMMY_FILE_OBJECT LocalFileObject;
1542 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
1543 HANDLE Handle;
1544 OPEN_PACKET OpenPacket;
1545 BOOLEAN IsBasic;
1546 PAGED_CODE();
1547 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
1548
1549 /* Check if the caller was user mode */
1550 if (AccessMode != KernelMode)
1551 {
1552 /* Protect probe in SEH */
1553 _SEH2_TRY
1554 {
1555 /* Probe the buffer */
1556 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
1557 }
1558 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1559 {
1560 /* Return the exception code */
1561 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1562 }
1563 _SEH2_END;
1564 }
1565
1566 /* Check if this is a basic or full request */
1567 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
1568
1569 /* Setup the Open Packet */
1570 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
1571 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
1572 OpenPacket.Size = sizeof(OPEN_PACKET);
1573 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
1574 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1575 OpenPacket.Disposition = FILE_OPEN;
1576 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
1577 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
1578 (AccessMode != KernelMode) ?
1579 &NetworkOpenInfo : FileInformation;
1580 OpenPacket.QueryOnly = TRUE;
1581 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
1582 OpenPacket.LocalFileObject = &LocalFileObject;
1583
1584 /* Update the operation count */
1585 IopUpdateOperationCount(IopOtherTransfer);
1586
1587 /*
1588 * Attempt opening the file. This will call the I/O Parse Routine for
1589 * the File Object (IopParseDevice) which will use the dummy file obejct
1590 * send the IRP to its device object. Note that we have two statuses
1591 * to worry about: the Object Manager's status (in Status) and the I/O
1592 * status, which is in the Open Packet's Final Status, and determined
1593 * by the Parse Check member.
1594 */
1595 Status = ObOpenObjectByName(ObjectAttributes,
1596 NULL,
1597 AccessMode,
1598 NULL,
1599 FILE_READ_ATTRIBUTES,
1600 &OpenPacket,
1601 &Handle);
1602 if (OpenPacket.ParseCheck != TRUE)
1603 {
1604 /* Parse failed */
1605 return Status;
1606 }
1607 else
1608 {
1609 /* Use the Io status */
1610 Status = OpenPacket.FinalStatus;
1611 }
1612
1613 /* Check if we were succesful and this was user mode and a full query */
1614 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
1615 {
1616 /* Enter SEH for copy */
1617 _SEH2_TRY
1618 {
1619 /* Copy the buffer back */
1620 RtlCopyMemory(FileInformation,
1621 &NetworkOpenInfo,
1622 FileInformationSize);
1623 }
1624 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1625 {
1626 /* Get exception code */
1627 Status = _SEH2_GetExceptionCode();
1628 }
1629 _SEH2_END;
1630 }
1631
1632 /* Return status */
1633 return Status;
1634 }
1635
1636 PVOID
1637 NTAPI
1638 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
1639 {
1640 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1641 {
1642 UNIMPLEMENTED;
1643 /* FIXME: return NULL for the moment ~ */
1644 return NULL;
1645 }
1646
1647 return NULL;
1648 }
1649
1650 NTSTATUS
1651 NTAPI
1652 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
1653 IN PVOID FilterContext,
1654 IN BOOLEAN Define)
1655 {
1656 if (!(FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION))
1657 {
1658 return STATUS_INVALID_PARAMETER;
1659 }
1660
1661 UNIMPLEMENTED;
1662
1663 return STATUS_NOT_IMPLEMENTED;
1664 }
1665
1666 /* FUNCTIONS *****************************************************************/
1667
1668 /*
1669 * @unimplemented
1670 */
1671 NTSTATUS
1672 NTAPI
1673 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
1674 IN ULONG Length,
1675 IN BOOLEAN SetOperation)
1676 {
1677 UNIMPLEMENTED;
1678 return STATUS_NOT_IMPLEMENTED;
1679 }
1680
1681 /*
1682 * @unimplemented
1683 */
1684 NTSTATUS
1685 NTAPI
1686 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
1687 IN ULONG QuotaLength,
1688 OUT PULONG ErrorOffset)
1689 {
1690 UNIMPLEMENTED;
1691 return STATUS_NOT_IMPLEMENTED;
1692 }
1693
1694 /*
1695 * @implemented
1696 */
1697 NTSTATUS
1698 NTAPI
1699 IoCreateFile(OUT PHANDLE FileHandle,
1700 IN ACCESS_MASK DesiredAccess,
1701 IN POBJECT_ATTRIBUTES ObjectAttributes,
1702 OUT PIO_STATUS_BLOCK IoStatusBlock,
1703 IN PLARGE_INTEGER AllocationSize OPTIONAL,
1704 IN ULONG FileAttributes,
1705 IN ULONG ShareAccess,
1706 IN ULONG Disposition,
1707 IN ULONG CreateOptions,
1708 IN PVOID EaBuffer OPTIONAL,
1709 IN ULONG EaLength,
1710 IN CREATE_FILE_TYPE CreateFileType,
1711 IN PVOID ExtraCreateParameters OPTIONAL,
1712 IN ULONG Options)
1713 {
1714 KPROCESSOR_MODE AccessMode;
1715 HANDLE LocalHandle = 0;
1716 LARGE_INTEGER SafeAllocationSize;
1717 NTSTATUS Status = STATUS_SUCCESS;
1718 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
1719 POPEN_PACKET OpenPacket;
1720 ULONG EaErrorOffset;
1721 PAGED_CODE();
1722 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
1723
1724
1725 /* Check if we have no parameter checking to do */
1726 if (Options & IO_NO_PARAMETER_CHECKING)
1727 {
1728 /* Then force kernel-mode access to avoid checks */
1729 AccessMode = KernelMode;
1730 }
1731 else
1732 {
1733 /* Otherwise, use the actual mode */
1734 AccessMode = ExGetPreviousMode();
1735 }
1736
1737 /* Check if we need to do parameter checking */
1738 if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
1739 {
1740 /* Validate parameters */
1741 if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
1742 {
1743 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
1744 return STATUS_INVALID_PARAMETER;
1745 }
1746
1747 if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
1748 {
1749 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
1750 return STATUS_INVALID_PARAMETER;
1751 }
1752
1753 if (Disposition > FILE_MAXIMUM_DISPOSITION)
1754 {
1755 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
1756 return STATUS_INVALID_PARAMETER;
1757 }
1758
1759 if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
1760 {
1761 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
1762 return STATUS_INVALID_PARAMETER;
1763 }
1764
1765 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
1766 (!(DesiredAccess & SYNCHRONIZE)))
1767 {
1768 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
1769 return STATUS_INVALID_PARAMETER;
1770 }
1771
1772 if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
1773 {
1774 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
1775 return STATUS_INVALID_PARAMETER;
1776 }
1777
1778 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
1779 (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
1780 {
1781 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
1782 return STATUS_INVALID_PARAMETER;
1783 }
1784
1785 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
1786 (CreateOptions & ~(FILE_DIRECTORY_FILE |
1787 FILE_SYNCHRONOUS_IO_ALERT |
1788 FILE_SYNCHRONOUS_IO_NONALERT |
1789 FILE_WRITE_THROUGH |
1790 FILE_COMPLETE_IF_OPLOCKED |
1791 FILE_OPEN_FOR_BACKUP_INTENT |
1792 FILE_DELETE_ON_CLOSE |
1793 FILE_OPEN_FOR_FREE_SPACE_QUERY |
1794 FILE_OPEN_BY_FILE_ID |
1795 FILE_NO_COMPRESSION |
1796 FILE_OPEN_REPARSE_POINT)))
1797 {
1798 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
1799 return STATUS_INVALID_PARAMETER;
1800 }
1801
1802 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
1803 (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
1804 {
1805 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
1806 return STATUS_INVALID_PARAMETER;
1807 }
1808
1809 if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
1810 {
1811 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
1812 return STATUS_INVALID_PARAMETER;
1813 }
1814
1815 if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
1816 {
1817 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
1818 return STATUS_INVALID_PARAMETER;
1819 }
1820
1821 /* Now check if this is a named pipe */
1822 if (CreateFileType == CreateFileTypeNamedPipe)
1823 {
1824 /* Make sure we have extra parameters */
1825 if (!ExtraCreateParameters)
1826 {
1827 return STATUS_INVALID_PARAMETER;
1828 }
1829
1830 /* Get the parameters and validate them */
1831 NamedPipeCreateParameters = ExtraCreateParameters;
1832 if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
1833 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
1834 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
1835 (ShareAccess & FILE_SHARE_DELETE) ||
1836 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
1837 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
1838 {
1839 /* Invalid named pipe create */
1840 return STATUS_INVALID_PARAMETER;
1841 }
1842 }
1843 else if (CreateFileType == CreateFileTypeMailslot)
1844 {
1845 /* Make sure we have extra parameters */
1846 if (!ExtraCreateParameters)
1847 {
1848 return STATUS_INVALID_PARAMETER;
1849 }
1850
1851 /* Get the parameters and validate them */
1852 if ((ShareAccess & FILE_SHARE_DELETE) ||
1853 !(ShareAccess & ~FILE_SHARE_WRITE) ||
1854 (Disposition != FILE_CREATE) ||
1855 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
1856 {
1857 /* Invalid mailslot create */
1858 return STATUS_INVALID_PARAMETER;
1859 }
1860 }
1861 }
1862
1863 /* Allocate the open packet */
1864 OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
1865 if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
1866 RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
1867
1868 /* Check if the call came from user mode */
1869 if (AccessMode != KernelMode)
1870 {
1871 _SEH2_TRY
1872 {
1873 /* Probe the output parameters */
1874 ProbeForWriteHandle(FileHandle);
1875 ProbeForWriteIoStatusBlock(IoStatusBlock);
1876
1877 /* Probe the allocation size if one was passed in */
1878 if (AllocationSize)
1879 {
1880 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
1881 }
1882 else
1883 {
1884 SafeAllocationSize.QuadPart = 0;
1885 }
1886
1887 /* Make sure it's valid */
1888 if (SafeAllocationSize.QuadPart < 0)
1889 {
1890 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
1891 }
1892
1893 /* Check if EA was passed in */
1894 if ((EaBuffer) && (EaLength))
1895 {
1896 /* Probe it */
1897 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
1898
1899 /* And marshall it */
1900 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
1901 EaLength,
1902 TAG_EA);
1903 OpenPacket->EaLength = EaLength;
1904 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
1905
1906 /* Validate the buffer */
1907 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
1908 EaLength,
1909 &EaErrorOffset);
1910 if (!NT_SUCCESS(Status))
1911 {
1912 /* Undo everything if it's invalid */
1913 DPRINT1("Invalid EA buffer\n");
1914 IoStatusBlock->Status = Status;
1915 IoStatusBlock->Information = EaErrorOffset;
1916 RtlRaiseStatus(Status);
1917 }
1918 }
1919 }
1920 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1921 {
1922 /* Return the exception code */
1923 if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
1924 ExFreePool(OpenPacket);
1925 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1926 }
1927 _SEH2_END;
1928 }
1929 else
1930 {
1931 /* Check if this is a device attach */
1932 if (CreateOptions & IO_ATTACH_DEVICE_API)
1933 {
1934 /* Set the flag properly */
1935 Options |= IO_ATTACH_DEVICE;
1936 CreateOptions &= ~IO_ATTACH_DEVICE_API;
1937 }
1938
1939 /* Check if we have allocation size */
1940 if (AllocationSize)
1941 {
1942 /* Capture it */
1943 SafeAllocationSize = *AllocationSize;
1944 }
1945 else
1946 {
1947 /* Otherwise, no size */
1948 SafeAllocationSize.QuadPart = 0;
1949 }
1950
1951 /* Check if we have an EA packet */
1952 if ((EaBuffer) && (EaLength))
1953 {
1954 /* Allocate the kernel copy */
1955 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
1956 EaLength,
1957 TAG_EA);
1958 if (!OpenPacket->EaBuffer)
1959 {
1960 ExFreePool(OpenPacket);
1961 return STATUS_INSUFFICIENT_RESOURCES;
1962 }
1963
1964 /* Copy the data */
1965 OpenPacket->EaLength = EaLength;
1966 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
1967
1968 /* Validate the buffer */
1969 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
1970 EaLength,
1971 &EaErrorOffset);
1972 if (!NT_SUCCESS(Status))
1973 {
1974 /* Undo everything if it's invalid */
1975 DPRINT1("Invalid EA buffer\n");
1976 ExFreePool(OpenPacket->EaBuffer);
1977 IoStatusBlock->Status = Status;
1978 IoStatusBlock->Information = EaErrorOffset;
1979 ExFreePool(OpenPacket);
1980 return Status;
1981 }
1982 }
1983 }
1984
1985 /* Setup the Open Packet */
1986 OpenPacket->Type = IO_TYPE_OPEN_PACKET;
1987 OpenPacket->Size = sizeof(*OpenPacket);
1988 OpenPacket->AllocationSize = SafeAllocationSize;
1989 OpenPacket->CreateOptions = CreateOptions;
1990 OpenPacket->FileAttributes = (USHORT)FileAttributes;
1991 OpenPacket->ShareAccess = (USHORT)ShareAccess;
1992 OpenPacket->Options = Options;
1993 OpenPacket->Disposition = Disposition;
1994 OpenPacket->CreateFileType = CreateFileType;
1995 OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
1996
1997 /* Update the operation count */
1998 IopUpdateOperationCount(IopOtherTransfer);
1999
2000 /*
2001 * Attempt opening the file. This will call the I/O Parse Routine for
2002 * the File Object (IopParseDevice) which will create the object and
2003 * send the IRP to its device object. Note that we have two statuses
2004 * to worry about: the Object Manager's status (in Status) and the I/O
2005 * status, which is in the Open Packet's Final Status, and determined
2006 * by the Parse Check member.
2007 */
2008 Status = ObOpenObjectByName(ObjectAttributes,
2009 NULL,
2010 AccessMode,
2011 NULL,
2012 DesiredAccess,
2013 OpenPacket,
2014 &LocalHandle);
2015
2016 /* Free the EA Buffer */
2017 if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2018
2019 /* Now check for Ob or Io failure */
2020 if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck != TRUE))
2021 {
2022 /* Check if Ob thinks well went well */
2023 if (NT_SUCCESS(Status))
2024 {
2025 /*
2026 * Tell it otherwise. Because we didn't use an ObjectType,
2027 * it incorrectly returned us a handle to God knows what.
2028 */
2029 ZwClose(LocalHandle);
2030 Status = STATUS_OBJECT_TYPE_MISMATCH;
2031 }
2032
2033 /* Now check the Io status */
2034 if (!NT_SUCCESS(OpenPacket->FinalStatus))
2035 {
2036 /* Use this status instead of Ob's */
2037 Status = OpenPacket->FinalStatus;
2038
2039 /* Check if it was only a warning */
2040 if (NT_WARNING(Status))
2041 {
2042 /* Protect write with SEH */
2043 _SEH2_TRY
2044 {
2045 /* In this case, we copy the I/O Status back */
2046 IoStatusBlock->Information = OpenPacket->Information;
2047 IoStatusBlock->Status = OpenPacket->FinalStatus;
2048 }
2049 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2050 {
2051 /* Get exception code */
2052 Status = _SEH2_GetExceptionCode();
2053 }
2054 _SEH2_END;
2055 }
2056 }
2057 else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck != 1))
2058 {
2059 /*
2060 * This can happen in the very bizarre case where the parse routine
2061 * actually executed more then once (due to a reparse) and ended
2062 * up failing after already having created the File Object.
2063 */
2064 if (OpenPacket->FileObject->FileName.Length)
2065 {
2066 /* It had a name, free it */
2067 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2068 }
2069
2070 /* Clear the device object to invalidate the FO, and dereference */
2071 OpenPacket->FileObject->DeviceObject = NULL;
2072 ObDereferenceObject(OpenPacket->FileObject);
2073 }
2074 }
2075 else
2076 {
2077 /* We reached success and have a valid file handle */
2078 OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2079 ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2080
2081 /* Enter SEH for write back */
2082 _SEH2_TRY
2083 {
2084 /* Write back the handle and I/O Status */
2085 *FileHandle = LocalHandle;
2086 IoStatusBlock->Information = OpenPacket->Information;
2087 IoStatusBlock->Status = OpenPacket->FinalStatus;
2088
2089 /* Get the Io status */
2090 Status = OpenPacket->FinalStatus;
2091 }
2092 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2093 {
2094 /* Get the exception status */
2095 Status = _SEH2_GetExceptionCode();
2096 }
2097 _SEH2_END;
2098 }
2099
2100 /* Check if we were 100% successful */
2101 if ((OpenPacket->ParseCheck == TRUE) && (OpenPacket->FileObject))
2102 {
2103 /* Dereference the File Object */
2104 ObDereferenceObject(OpenPacket->FileObject);
2105 }
2106
2107 /* Return status */
2108 ExFreePool(OpenPacket);
2109 return Status;
2110 }
2111
2112 /*
2113 * @unimplemented
2114 */
2115 NTSTATUS
2116 NTAPI
2117 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
2118 IN ACCESS_MASK DesiredAccess,
2119 IN POBJECT_ATTRIBUTES ObjectAttributes,
2120 OUT PIO_STATUS_BLOCK IoStatusBlock,
2121 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2122 IN ULONG FileAttributes,
2123 IN ULONG ShareAccess,
2124 IN ULONG Disposition,
2125 IN ULONG CreateOptions,
2126 IN PVOID EaBuffer OPTIONAL,
2127 IN ULONG EaLength,
2128 IN CREATE_FILE_TYPE CreateFileType,
2129 IN PVOID ExtraCreateParameters OPTIONAL,
2130 IN ULONG Options,
2131 IN PVOID DeviceObject)
2132 {
2133 UNIMPLEMENTED;
2134 return STATUS_NOT_IMPLEMENTED;
2135 }
2136
2137 /*
2138 * @implemented
2139 */
2140 PFILE_OBJECT
2141 NTAPI
2142 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
2143 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
2144 OUT PHANDLE FileObjectHandle OPTIONAL)
2145 {
2146 PFILE_OBJECT CreatedFileObject;
2147 NTSTATUS Status;
2148 HANDLE FileHandle;
2149 OBJECT_ATTRIBUTES ObjectAttributes;
2150 PAGED_CODE();
2151 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2152
2153 /* Choose Device Object */
2154 if (FileObject) DeviceObject = FileObject->DeviceObject;
2155
2156 /* Reference the device object and initialize attributes */
2157 InterlockedIncrement(&DeviceObject->ReferenceCount);
2158 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2159
2160 /* Create the File Object */
2161 Status = ObCreateObject(KernelMode,
2162 IoFileObjectType,
2163 &ObjectAttributes,
2164 KernelMode,
2165 NULL,
2166 sizeof(FILE_OBJECT),
2167 sizeof(FILE_OBJECT),
2168 0,
2169 (PVOID*)&CreatedFileObject);
2170 if (!NT_SUCCESS(Status))
2171 {
2172 /* Fail */
2173 IopDereferenceDeviceObject(DeviceObject, FALSE);
2174 ExRaiseStatus(Status);
2175 }
2176
2177 /* Set File Object Data */
2178 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2179 CreatedFileObject->DeviceObject = DeviceObject;
2180 CreatedFileObject->Type = IO_TYPE_FILE;
2181 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2182 CreatedFileObject->Flags = FO_STREAM_FILE;
2183
2184 /* Initialize the wait event */
2185 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2186
2187 /* Insert it to create a handle for it */
2188 Status = ObInsertObject(CreatedFileObject,
2189 NULL,
2190 FILE_READ_DATA,
2191 1,
2192 (PVOID*)&CreatedFileObject,
2193 &FileHandle);
2194 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
2195
2196 /* Set the handle created flag */
2197 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2198 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2199
2200 /* Check if we have a VPB */
2201 if (DeviceObject->Vpb)
2202 {
2203 /* Reference it */
2204 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2205 }
2206
2207 /* Check if the caller wants the handle */
2208 if (FileObjectHandle)
2209 {
2210 /* Return it */
2211 *FileObjectHandle = FileHandle;
2212 ObDereferenceObject(CreatedFileObject);
2213 }
2214 else
2215 {
2216 /* Otherwise, close it */
2217 ObCloseHandle(FileHandle, KernelMode);
2218 }
2219
2220 /* Return the file object */
2221 return CreatedFileObject;
2222 }
2223
2224 /*
2225 * @implemented
2226 */
2227 PFILE_OBJECT
2228 NTAPI
2229 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
2230 IN PDEVICE_OBJECT DeviceObject)
2231 {
2232 /* Call the newer function */
2233 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
2234 }
2235
2236 /*
2237 * @implemented
2238 */
2239 PFILE_OBJECT
2240 NTAPI
2241 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
2242 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2243 {
2244 PFILE_OBJECT CreatedFileObject;
2245 NTSTATUS Status;
2246 OBJECT_ATTRIBUTES ObjectAttributes;
2247 PAGED_CODE();
2248 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2249
2250 /* Choose Device Object */
2251 if (FileObject) DeviceObject = FileObject->DeviceObject;
2252
2253 /* Reference the device object and initialize attributes */
2254 InterlockedIncrement(&DeviceObject->ReferenceCount);
2255 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2256
2257 /* Create the File Object */
2258 Status = ObCreateObject(KernelMode,
2259 IoFileObjectType,
2260 &ObjectAttributes,
2261 KernelMode,
2262 NULL,
2263 sizeof(FILE_OBJECT),
2264 sizeof(FILE_OBJECT),
2265 0,
2266 (PVOID*)&CreatedFileObject);
2267 if (!NT_SUCCESS(Status))
2268 {
2269 /* Fail */
2270 IopDereferenceDeviceObject(DeviceObject, FALSE);
2271 ExRaiseStatus(Status);
2272 }
2273
2274 /* Set File Object Data */
2275 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2276 CreatedFileObject->DeviceObject = DeviceObject;
2277 CreatedFileObject->Type = IO_TYPE_FILE;
2278 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2279 CreatedFileObject->Flags = FO_STREAM_FILE;
2280
2281 /* Initialize the wait event */
2282 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2283
2284 /* Destroy create information */
2285 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
2286 ObjectCreateInfo);
2287 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
2288
2289 /* Set the handle created flag */
2290 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2291 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2292
2293 /* Check if we have a VPB */
2294 if (DeviceObject->Vpb)
2295 {
2296 /* Reference it */
2297 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2298 }
2299
2300 /* Return the file object */
2301 return CreatedFileObject;
2302 }
2303
2304 /*
2305 * @implemented
2306 */
2307 PGENERIC_MAPPING
2308 NTAPI
2309 IoGetFileObjectGenericMapping(VOID)
2310 {
2311 /* Return the mapping */
2312 return &IopFileMapping;
2313 }
2314
2315 /*
2316 * @implemented
2317 */
2318 BOOLEAN
2319 NTAPI
2320 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
2321 {
2322 /* Return the flag status */
2323 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2324 }
2325
2326 /*
2327 * @implemented
2328 */
2329 BOOLEAN
2330 NTAPI
2331 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
2332 IN ACCESS_MASK DesiredAccess,
2333 IN ULONG OpenOptions,
2334 OUT PIO_STATUS_BLOCK IoStatus,
2335 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
2336 {
2337 NTSTATUS Status;
2338 DUMMY_FILE_OBJECT LocalFileObject;
2339 HANDLE Handle;
2340 OPEN_PACKET OpenPacket;
2341 PAGED_CODE();
2342 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2343
2344 /* Setup the Open Packet */
2345 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2346 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2347 OpenPacket.Size = sizeof(OPEN_PACKET);
2348 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
2349 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2350 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
2351 OpenPacket.Disposition = FILE_OPEN;
2352 OpenPacket.NetworkInformation = Buffer;
2353 OpenPacket.QueryOnly = TRUE;
2354 OpenPacket.FullAttributes = TRUE;
2355 OpenPacket.LocalFileObject = &LocalFileObject;
2356
2357 /*
2358 * Attempt opening the file. This will call the I/O Parse Routine for
2359 * the File Object (IopParseDevice) which will use the dummy file obejct
2360 * send the IRP to its device object. Note that we have two statuses
2361 * to worry about: the Object Manager's status (in Status) and the I/O
2362 * status, which is in the Open Packet's Final Status, and determined
2363 * by the Parse Check member.
2364 */
2365 Status = ObOpenObjectByName(ObjectAttributes,
2366 NULL,
2367 KernelMode,
2368 NULL,
2369 DesiredAccess,
2370 &OpenPacket,
2371 &Handle);
2372 if (OpenPacket.ParseCheck != TRUE)
2373 {
2374 /* Parse failed */
2375 IoStatus->Status = Status;
2376 }
2377 else
2378 {
2379 /* Use the Io status */
2380 IoStatus->Status = OpenPacket.FinalStatus;
2381 IoStatus->Information = OpenPacket.Information;
2382 }
2383
2384 /* Return success */
2385 return TRUE;
2386 }
2387
2388 /*
2389 * @implemented
2390 */
2391 VOID
2392 NTAPI
2393 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
2394 OUT PSHARE_ACCESS ShareAccess)
2395 {
2396 PAGED_CODE();
2397
2398 /* Check if the file has an extension */
2399 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2400 {
2401 /* Check if caller specified to ignore access checks */
2402 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2403 {
2404 /* Don't update share access */
2405 return;
2406 }
2407 }
2408
2409 /* Otherwise, check if there's any access present */
2410 if ((FileObject->ReadAccess) ||
2411 (FileObject->WriteAccess) ||
2412 (FileObject->DeleteAccess))
2413 {
2414 /* Increase the open count */
2415 ShareAccess->OpenCount++;
2416
2417 /* Add new share access */
2418 ShareAccess->Readers += FileObject->ReadAccess;
2419 ShareAccess->Writers += FileObject->WriteAccess;
2420 ShareAccess->Deleters += FileObject->DeleteAccess;
2421 ShareAccess->SharedRead += FileObject->SharedRead;
2422 ShareAccess->SharedWrite += FileObject->SharedWrite;
2423 ShareAccess->SharedDelete += FileObject->SharedDelete;
2424 }
2425 }
2426
2427 /*
2428 * @implemented
2429 */
2430 NTSTATUS
2431 NTAPI
2432 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
2433 IN ULONG DesiredShareAccess,
2434 IN PFILE_OBJECT FileObject,
2435 IN PSHARE_ACCESS ShareAccess,
2436 IN BOOLEAN Update)
2437 {
2438 BOOLEAN ReadAccess;
2439 BOOLEAN WriteAccess;
2440 BOOLEAN DeleteAccess;
2441 BOOLEAN SharedRead;
2442 BOOLEAN SharedWrite;
2443 BOOLEAN SharedDelete;
2444 PAGED_CODE();
2445
2446 /* Get access masks */
2447 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
2448 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
2449 DeleteAccess = (DesiredAccess & DELETE) != 0;
2450
2451 /* Set them in the file object */
2452 FileObject->ReadAccess = ReadAccess;
2453 FileObject->WriteAccess = WriteAccess;
2454 FileObject->DeleteAccess = DeleteAccess;
2455
2456 /* Check if the file has an extension */
2457 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2458 {
2459 /* Check if caller specified to ignore access checks */
2460 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2461 {
2462 /* Don't check share access */
2463 return STATUS_SUCCESS;
2464 }
2465 }
2466
2467 /* Check if we have any access */
2468 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
2469 {
2470 /* Get shared access masks */
2471 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
2472 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
2473 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
2474
2475 /* Set them */
2476 FileObject->SharedRead = SharedRead;
2477 FileObject->SharedWrite = SharedWrite;
2478 FileObject->SharedDelete = SharedDelete;
2479
2480 /* Check if the shared access is violated */
2481 if ((ReadAccess &&
2482 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
2483 (WriteAccess &&
2484 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
2485 (DeleteAccess &&
2486 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
2487 ((ShareAccess->Readers != 0) && !SharedRead) ||
2488 ((ShareAccess->Writers != 0) && !SharedWrite) ||
2489 ((ShareAccess->Deleters != 0) && !SharedDelete))
2490 {
2491 /* Sharing violation, fail */
2492 return STATUS_SHARING_VIOLATION;
2493 }
2494
2495 /* It's not, check if caller wants us to update it */
2496 if (Update)
2497 {
2498 /* Increase open count */
2499 ShareAccess->OpenCount++;
2500
2501 /* Update shared access */
2502 ShareAccess->Readers += ReadAccess;
2503 ShareAccess->Writers += WriteAccess;
2504 ShareAccess->Deleters += DeleteAccess;
2505 ShareAccess->SharedRead += SharedRead;
2506 ShareAccess->SharedWrite += SharedWrite;
2507 ShareAccess->SharedDelete += SharedDelete;
2508 }
2509 }
2510
2511 /* Validation successful */
2512 return STATUS_SUCCESS;
2513 }
2514
2515 /*
2516 * @implemented
2517 */
2518 VOID
2519 NTAPI
2520 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
2521 IN PSHARE_ACCESS ShareAccess)
2522 {
2523 PAGED_CODE();
2524
2525 /* Check if the file has an extension */
2526 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2527 {
2528 /* Check if caller specified to ignore access checks */
2529 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2530 {
2531 /* Don't update share access */
2532 return;
2533 }
2534 }
2535
2536 /* Otherwise, check if there's any access present */
2537 if ((FileObject->ReadAccess) ||
2538 (FileObject->WriteAccess) ||
2539 (FileObject->DeleteAccess))
2540 {
2541 /* Decrement the open count */
2542 ShareAccess->OpenCount--;
2543
2544 /* Remove share access */
2545 ShareAccess->Readers -= FileObject->ReadAccess;
2546 ShareAccess->Writers -= FileObject->WriteAccess;
2547 ShareAccess->Deleters -= FileObject->DeleteAccess;
2548 ShareAccess->SharedRead -= FileObject->SharedRead;
2549 ShareAccess->SharedWrite -= FileObject->SharedWrite;
2550 ShareAccess->SharedDelete -= FileObject->SharedDelete;
2551 }
2552 }
2553
2554 /*
2555 * @implemented
2556 */
2557 VOID
2558 NTAPI
2559 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
2560 IN ULONG DesiredShareAccess,
2561 IN PFILE_OBJECT FileObject,
2562 OUT PSHARE_ACCESS ShareAccess)
2563 {
2564 BOOLEAN ReadAccess;
2565 BOOLEAN WriteAccess;
2566 BOOLEAN DeleteAccess;
2567 BOOLEAN SharedRead;
2568 BOOLEAN SharedWrite;
2569 BOOLEAN SharedDelete;
2570 BOOLEAN Update = TRUE;
2571 PAGED_CODE();
2572
2573 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
2574 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
2575 DeleteAccess = (DesiredAccess & DELETE) != 0;
2576
2577 /* Check if the file has an extension */
2578 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2579 {
2580 /* Check if caller specified to ignore access checks */
2581 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2582 {
2583 /* Don't update share access */
2584 Update = FALSE;
2585 }
2586 }
2587
2588 /* Update basic access */
2589 FileObject->ReadAccess = ReadAccess;
2590 FileObject->WriteAccess = WriteAccess;
2591 FileObject->DeleteAccess = DeleteAccess;
2592
2593 /* Check if we have no access as all */
2594 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
2595 {
2596 /* Check if we need to update the structure */
2597 if (!Update) return;
2598
2599 /* Otherwise, clear data */
2600 ShareAccess->OpenCount = 0;
2601 ShareAccess->Readers = 0;
2602 ShareAccess->Writers = 0;
2603 ShareAccess->Deleters = 0;
2604 ShareAccess->SharedRead = 0;
2605 ShareAccess->SharedWrite = 0;
2606 ShareAccess->SharedDelete = 0;
2607 }
2608 else
2609 {
2610 /* Calculate shared access */
2611 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
2612 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
2613 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
2614
2615 /* Set it in the FO */
2616 FileObject->SharedRead = SharedRead;
2617 FileObject->SharedWrite = SharedWrite;
2618 FileObject->SharedDelete = SharedDelete;
2619
2620 /* Check if we need to update the structure */
2621 if (!Update) return;
2622
2623 /* Otherwise, set data */
2624 ShareAccess->OpenCount = 1;
2625 ShareAccess->Readers = ReadAccess;
2626 ShareAccess->Writers = WriteAccess;
2627 ShareAccess->Deleters = DeleteAccess;
2628 ShareAccess->SharedRead = SharedRead;
2629 ShareAccess->SharedWrite = SharedWrite;
2630 ShareAccess->SharedDelete = SharedDelete;
2631 }
2632 }
2633
2634 /*
2635 * @implemented
2636 */
2637 VOID
2638 NTAPI
2639 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
2640 IN PFILE_OBJECT FileObject)
2641 {
2642 PIRP Irp;
2643 KEVENT Event;
2644 KIRQL OldIrql;
2645 NTSTATUS Status;
2646 PIO_STACK_LOCATION Stack;
2647
2648 /* Check if handles were already created for the
2649 * open file. If so, that's over.
2650 */
2651 if (FileObject->Flags & FO_HANDLE_CREATED)
2652 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
2653 (ULONG_PTR)FileObject,
2654 (ULONG_PTR)DeviceObject, 0, 0);
2655
2656 /* Reset the events */
2657 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2658 KeClearEvent(&FileObject->Event);
2659
2660 /* Allocate the IRP we'll use */
2661 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2662 /* Properly set it */
2663 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2664 Irp->UserEvent = &Event;
2665 Irp->UserIosb = &Irp->IoStatus;
2666 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2667 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2668 Irp->RequestorMode = KernelMode;
2669 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2670
2671 Stack = IoGetNextIrpStackLocation(Irp);
2672 Stack->MajorFunction = IRP_MJ_CLEANUP;
2673 Stack->FileObject = FileObject;
2674
2675 /* Put on top of IRPs list of the thread */
2676 IopQueueIrpToThread(Irp);
2677
2678 /* Call the driver */
2679 Status = IoCallDriver(DeviceObject, Irp);
2680 if (Status == STATUS_PENDING)
2681 {
2682 KeWaitForSingleObject(&Event, UserRequest,
2683 KernelMode, FALSE, NULL);
2684 }
2685
2686 /* Remove from IRPs list */
2687 KeRaiseIrql(APC_LEVEL, &OldIrql);
2688 IopUnQueueIrpFromThread(Irp);
2689 KeLowerIrql(OldIrql);
2690
2691 /* Free the IRP */
2692 IoFreeIrp(Irp);
2693
2694 /* Clear the event */
2695 KeClearEvent(&FileObject->Event);
2696 /* And finally, mark the open operation as canceled */
2697 FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
2698 }
2699
2700 /*
2701 * @unimplemented
2702 */
2703 NTSTATUS
2704 NTAPI
2705 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
2706 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
2707 {
2708 UNIMPLEMENTED;
2709 return STATUS_NOT_IMPLEMENTED;
2710 }
2711
2712 /*
2713 * @implemented
2714 */
2715 NTSTATUS
2716 NTAPI
2717 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
2718 IN BOOLEAN Remote)
2719 {
2720 NTSTATUS Status = STATUS_SUCCESS;
2721 BOOLEAN FlagSet;
2722
2723 /* Get the flag status */
2724 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2725
2726 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
2727 if (Remote && !FlagSet)
2728 {
2729 /* Set the flag */
2730 FileObject->Flags |= FO_REMOTE_ORIGIN;
2731 }
2732 else if (!Remote && FlagSet)
2733 {
2734 /* Remove the flag */
2735 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
2736 }
2737 else
2738 {
2739 /* Fail */
2740 Status = STATUS_INVALID_PARAMETER_MIX;
2741 }
2742
2743 /* Return status */
2744 return Status;
2745 }
2746
2747 /*
2748 * @implemented
2749 */
2750 NTSTATUS
2751 NTAPI
2752 NtCreateFile(PHANDLE FileHandle,
2753 ACCESS_MASK DesiredAccess,
2754 POBJECT_ATTRIBUTES ObjectAttributes,
2755 PIO_STATUS_BLOCK IoStatusBlock,
2756 PLARGE_INTEGER AllocateSize,
2757 ULONG FileAttributes,
2758 ULONG ShareAccess,
2759 ULONG CreateDisposition,
2760 ULONG CreateOptions,
2761 PVOID EaBuffer,
2762 ULONG EaLength)
2763 {
2764 /* Call the I/O Function */
2765 return IoCreateFile(FileHandle,
2766 DesiredAccess,
2767 ObjectAttributes,
2768 IoStatusBlock,
2769 AllocateSize,
2770 FileAttributes,
2771 ShareAccess,
2772 CreateDisposition,
2773 CreateOptions,
2774 EaBuffer,
2775 EaLength,
2776 CreateFileTypeNone,
2777 NULL,
2778 0);
2779 }
2780
2781 NTSTATUS
2782 NTAPI
2783 NtCreateMailslotFile(OUT PHANDLE FileHandle,
2784 IN ACCESS_MASK DesiredAccess,
2785 IN POBJECT_ATTRIBUTES ObjectAttributes,
2786 OUT PIO_STATUS_BLOCK IoStatusBlock,
2787 IN ULONG CreateOptions,
2788 IN ULONG MailslotQuota,
2789 IN ULONG MaxMessageSize,
2790 IN PLARGE_INTEGER TimeOut)
2791 {
2792 MAILSLOT_CREATE_PARAMETERS Buffer;
2793 PAGED_CODE();
2794
2795 /* Check for Timeout */
2796 if (TimeOut)
2797 {
2798 /* check if the call came from user mode */
2799 if (KeGetPreviousMode() != KernelMode)
2800 {
2801 /* Enter SEH for Probe */
2802 _SEH2_TRY
2803 {
2804 /* Probe the timeout */
2805 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
2806 }
2807 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2808 {
2809 /* Return the exception code */
2810 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2811 }
2812 _SEH2_END;
2813 }
2814 else
2815 {
2816 /* Otherwise, capture directly */
2817 Buffer.ReadTimeout = *TimeOut;
2818 }
2819
2820 /* Set the correct setting */
2821 Buffer.TimeoutSpecified = TRUE;
2822 }
2823 else
2824 {
2825 /* Tell the FSD we don't have a timeout */
2826 Buffer.TimeoutSpecified = FALSE;
2827 }
2828
2829 /* Set Settings */
2830 Buffer.MailslotQuota = MailslotQuota;
2831 Buffer.MaximumMessageSize = MaxMessageSize;
2832
2833 /* Call I/O */
2834 return IoCreateFile(FileHandle,
2835 DesiredAccess,
2836 ObjectAttributes,
2837 IoStatusBlock,
2838 NULL,
2839 0,
2840 FILE_SHARE_READ | FILE_SHARE_WRITE,
2841 FILE_CREATE,
2842 CreateOptions,
2843 NULL,
2844 0,
2845 CreateFileTypeMailslot,
2846 (PVOID)&Buffer,
2847 0);
2848 }
2849
2850 NTSTATUS
2851 NTAPI
2852 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
2853 IN ACCESS_MASK DesiredAccess,
2854 IN POBJECT_ATTRIBUTES ObjectAttributes,
2855 OUT PIO_STATUS_BLOCK IoStatusBlock,
2856 IN ULONG ShareAccess,
2857 IN ULONG CreateDisposition,
2858 IN ULONG CreateOptions,
2859 IN ULONG NamedPipeType,
2860 IN ULONG ReadMode,
2861 IN ULONG CompletionMode,
2862 IN ULONG MaximumInstances,
2863 IN ULONG InboundQuota,
2864 IN ULONG OutboundQuota,
2865 IN PLARGE_INTEGER DefaultTimeout)
2866 {
2867 NAMED_PIPE_CREATE_PARAMETERS Buffer;
2868 PAGED_CODE();
2869
2870 /* Check for Timeout */
2871 if (DefaultTimeout)
2872 {
2873 /* check if the call came from user mode */
2874 if (KeGetPreviousMode() != KernelMode)
2875 {
2876 /* Enter SEH for Probe */
2877 _SEH2_TRY
2878 {
2879 /* Probe the timeout */
2880 Buffer.DefaultTimeout =
2881 ProbeForReadLargeInteger(DefaultTimeout);
2882 }
2883 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2884 {
2885 /* Return the exception code */
2886 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2887 }
2888 _SEH2_END;
2889 }
2890 else
2891 {
2892 /* Otherwise, capture directly */
2893 Buffer.DefaultTimeout = *DefaultTimeout;
2894 }
2895
2896 /* Set the correct setting */
2897 Buffer.TimeoutSpecified = TRUE;
2898 }
2899 else
2900 {
2901 /* Tell the FSD we don't have a timeout */
2902 Buffer.TimeoutSpecified = FALSE;
2903 }
2904
2905 /* Set Settings */
2906 Buffer.NamedPipeType = NamedPipeType;
2907 Buffer.ReadMode = ReadMode;
2908 Buffer.CompletionMode = CompletionMode;
2909 Buffer.MaximumInstances = MaximumInstances;
2910 Buffer.InboundQuota = InboundQuota;
2911 Buffer.OutboundQuota = OutboundQuota;
2912
2913 /* Call I/O */
2914 return IoCreateFile(FileHandle,
2915 DesiredAccess,
2916 ObjectAttributes,
2917 IoStatusBlock,
2918 NULL,
2919 0,
2920 ShareAccess,
2921 CreateDisposition,
2922 CreateOptions,
2923 NULL,
2924 0,
2925 CreateFileTypeNamedPipe,
2926 (PVOID)&Buffer,
2927 0);
2928 }
2929
2930 NTSTATUS
2931 NTAPI
2932 NtFlushWriteBuffer(VOID)
2933 {
2934 PAGED_CODE();
2935
2936 /* Call the kernel */
2937 KeFlushWriteBuffer();
2938 return STATUS_SUCCESS;
2939 }
2940
2941 /*
2942 * @implemented
2943 */
2944 NTSTATUS
2945 NTAPI
2946 NtOpenFile(OUT PHANDLE FileHandle,
2947 IN ACCESS_MASK DesiredAccess,
2948 IN POBJECT_ATTRIBUTES ObjectAttributes,
2949 OUT PIO_STATUS_BLOCK IoStatusBlock,
2950 IN ULONG ShareAccess,
2951 IN ULONG OpenOptions)
2952 {
2953 /* Call the I/O Function */
2954 return IoCreateFile(FileHandle,
2955 DesiredAccess,
2956 ObjectAttributes,
2957 IoStatusBlock,
2958 NULL,
2959 0,
2960 ShareAccess,
2961 FILE_OPEN,
2962 OpenOptions,
2963 NULL,
2964 0,
2965 CreateFileTypeNone,
2966 NULL,
2967 0);
2968 }
2969
2970 NTSTATUS
2971 NTAPI
2972 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2973 OUT PFILE_BASIC_INFORMATION FileInformation)
2974 {
2975 /* Call the internal helper API */
2976 return IopQueryAttributesFile(ObjectAttributes,
2977 FileBasicInformation,
2978 sizeof(FILE_BASIC_INFORMATION),
2979 FileInformation);
2980 }
2981
2982 NTSTATUS
2983 NTAPI
2984 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2985 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
2986 {
2987 /* Call the internal helper API */
2988 return IopQueryAttributesFile(ObjectAttributes,
2989 FileNetworkOpenInformation,
2990 sizeof(FILE_NETWORK_OPEN_INFORMATION),
2991 FileInformation);
2992 }
2993
2994 /**
2995 * @name NtCancelIoFile
2996 *
2997 * Cancel all pending I/O operations in the current thread for specified
2998 * file object.
2999 *
3000 * @param FileHandle
3001 * Handle to file object to cancel requests for. No specific
3002 * access rights are needed.
3003 * @param IoStatusBlock
3004 * Pointer to status block which is filled with final completition
3005 * status on successful return.
3006 *
3007 * @return Status.
3008 *
3009 * @implemented
3010 */
3011 NTSTATUS
3012 NTAPI
3013 NtCancelIoFile(IN HANDLE FileHandle,
3014 OUT PIO_STATUS_BLOCK IoStatusBlock)
3015 {
3016 PFILE_OBJECT FileObject;
3017 PETHREAD Thread;
3018 PIRP Irp;
3019 KIRQL OldIrql;
3020 BOOLEAN OurIrpsInList = FALSE;
3021 LARGE_INTEGER Interval;
3022 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
3023 NTSTATUS Status;
3024 PLIST_ENTRY ListHead, NextEntry;
3025 PAGED_CODE();
3026 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
3027
3028 /* Check the previous mode */
3029 if (PreviousMode != KernelMode)
3030 {
3031 /* Enter SEH for probing */
3032 _SEH2_TRY
3033 {
3034 /* Probe the I/O Status Block */
3035 ProbeForWriteIoStatusBlock(IoStatusBlock);
3036 }
3037 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3038 {
3039 /* Return the exception code */
3040 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3041 }
3042 _SEH2_END;
3043 }
3044
3045 /* Reference the file object */
3046 Status = ObReferenceObjectByHandle(FileHandle,
3047 0,
3048 IoFileObjectType,
3049 PreviousMode,
3050 (PVOID*)&FileObject,
3051 NULL);
3052 if (!NT_SUCCESS(Status)) return Status;
3053
3054 /* IRP cancellations are synchronized at APC_LEVEL. */
3055 KeRaiseIrql(APC_LEVEL, &OldIrql);
3056
3057 /* Get the current thread */
3058 Thread = PsGetCurrentThread();
3059
3060 /* Update the operation counts */
3061 IopUpdateOperationCount(IopOtherTransfer);
3062
3063 /* Loop the list */
3064 ListHead = &Thread->IrpList;
3065 NextEntry = ListHead->Flink;
3066 while (ListHead != NextEntry)
3067 {
3068 /* Get the IRP and check if the File Object matches */
3069 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
3070 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
3071 {
3072 /* Cancel this IRP and keep looping */
3073 IoCancelIrp(Irp);
3074 OurIrpsInList = TRUE;
3075 }
3076
3077 /* Go to the next entry */
3078 NextEntry = NextEntry->Flink;
3079 }
3080
3081 /* Lower the IRQL */
3082 KeLowerIrql(OldIrql);
3083
3084 /* Check if we had found an IRP */
3085 if (OurIrpsInList)
3086 {
3087 /* Setup a 10ms wait */
3088 Interval.QuadPart = -100000;
3089
3090 /* Start looping */
3091 while (OurIrpsInList)
3092 {
3093 /* Do the wait */
3094 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
3095 OurIrpsInList = FALSE;
3096
3097 /* Raise IRQL */
3098 KeRaiseIrql(APC_LEVEL, &OldIrql);
3099
3100 /* Now loop the list again */
3101 NextEntry = ListHead->Flink;
3102 while (NextEntry != ListHead)
3103 {
3104 /* Get the IRP and check if the File Object matches */
3105 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
3106 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
3107 {
3108 /* Keep looping */
3109 OurIrpsInList = TRUE;
3110 break;
3111 }
3112
3113 /* Go to the next entry */
3114 NextEntry = NextEntry->Flink;
3115 }
3116
3117 /* Lower the IRQL */
3118 KeLowerIrql(OldIrql);
3119 }
3120 }
3121
3122 /* Enter SEH for writing back the I/O Status */
3123 _SEH2_TRY
3124 {
3125 /* Write success */
3126 IoStatusBlock->Status = STATUS_SUCCESS;
3127 IoStatusBlock->Information = 0;
3128 }
3129 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3130 {
3131 /* Ignore exception */
3132 }
3133 _SEH2_END;
3134
3135 /* Dereference the file object and return success */
3136 ObDereferenceObject(FileObject);
3137 return STATUS_SUCCESS;
3138 }
3139
3140 /*
3141 * @implemented
3142 */
3143 NTSTATUS
3144 NTAPI
3145 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
3146 {
3147 NTSTATUS Status;
3148 DUMMY_FILE_OBJECT LocalFileObject;
3149 HANDLE Handle;
3150 KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
3151 OPEN_PACKET OpenPacket;
3152 PAGED_CODE();
3153 IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
3154
3155 /* Setup the Open Packet */
3156 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3157 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3158 OpenPacket.Size = sizeof(OPEN_PACKET);
3159 OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
3160 OpenPacket.ShareAccess = FILE_SHARE_READ |
3161 FILE_SHARE_WRITE |
3162 FILE_SHARE_DELETE;
3163 OpenPacket.Disposition = FILE_OPEN;
3164 OpenPacket.DeleteOnly = TRUE;
3165 OpenPacket.LocalFileObject = &LocalFileObject;
3166
3167 /* Update the operation counts */
3168 IopUpdateOperationCount(IopOtherTransfer);
3169
3170 /*
3171 * Attempt opening the file. This will call the I/O Parse Routine for
3172 * the File Object (IopParseDevice) which will use the dummy file obejct
3173 * send the IRP to its device object. Note that we have two statuses
3174 * to worry about: the Object Manager's status (in Status) and the I/O
3175 * status, which is in the Open Packet's Final Status, and determined
3176 * by the Parse Check member.
3177 */
3178 Status = ObOpenObjectByName(ObjectAttributes,
3179 NULL,
3180 AccessMode,
3181 NULL,
3182 DELETE,
3183 &OpenPacket,
3184 &Handle);
3185 if (OpenPacket.ParseCheck != TRUE) return Status;
3186
3187 /* Retrn the Io status */
3188 return OpenPacket.FinalStatus;
3189 }
3190
3191 /* EOF */