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