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