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