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