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