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