* Sync up to trunk r55544.
[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 return STATUS_INFO_LENGTH_MISMATCH;
1321 }
1322
1323 /* Allocate Buffer */
1324 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1325 if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1326
1327 /* Query the name */
1328 Status = ObQueryNameString(FileObject->DeviceObject,
1329 LocalInfo,
1330 Length,
1331 &LocalReturnLength);
1332 if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
1333 {
1334 /* Free the buffer and fail */
1335 ExFreePoolWithTag(LocalInfo, TAG_IO);
1336 return Status;
1337 }
1338
1339 /* Copy the information */
1340 RtlCopyMemory(ObjectNameInfo,
1341 LocalInfo,
1342 (LocalReturnLength > Length) ?
1343 Length : LocalReturnLength);
1344
1345 /* Set buffer pointer */
1346 p = (PWCHAR)(ObjectNameInfo + 1);
1347 ObjectNameInfo->Name.Buffer = p;
1348
1349 /* Advance in buffer */
1350 p += (LocalInfo->Name.Length / sizeof(WCHAR));
1351
1352 /* Check if this already filled our buffer */
1353 if (LocalReturnLength > Length)
1354 {
1355 /* Set the length mismatch to true, so that we can return
1356 * the proper buffer size to the caller later
1357 */
1358 LengthMismatch = TRUE;
1359
1360 /* Save the initial buffer length value */
1361 *ReturnLength = LocalReturnLength;
1362 }
1363
1364 /* Now get the file name buffer and check the length needed */
1365 LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
1366 FileLength = Length -
1367 LocalReturnLength +
1368 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
1369
1370 /* Query the File name */
1371 Status = IoQueryFileInformation(FileObject,
1372 FileNameInformation,
1373 LengthMismatch ? Length : FileLength,
1374 LocalFileInfo,
1375 &LocalReturnLength);
1376 if (NT_ERROR(Status))
1377 {
1378 /* Fail on errors only, allow warnings */
1379 ExFreePoolWithTag(LocalInfo, TAG_IO);
1380 return Status;
1381 }
1382
1383 /* If the provided buffer is too small, return the required size */
1384 if (LengthMismatch)
1385 {
1386 /* Add the required length */
1387 *ReturnLength += LocalFileInfo->FileNameLength;
1388
1389 /* Free the allocated buffer and return failure */
1390 ExFreePoolWithTag(LocalInfo, TAG_IO);
1391 return STATUS_BUFFER_OVERFLOW;
1392 }
1393
1394 /* Now calculate the new lengths left */
1395 FileLength = LocalReturnLength -
1396 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
1397 LocalReturnLength = (ULONG)((ULONG_PTR)p -
1398 (ULONG_PTR)ObjectNameInfo +
1399 LocalFileInfo->FileNameLength);
1400
1401 /* Write the Name and null-terminate it */
1402 RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
1403 p += (FileLength / sizeof(WCHAR));
1404 *p = UNICODE_NULL;
1405 LocalReturnLength += sizeof(UNICODE_NULL);
1406
1407 /* Return the length needed */
1408 *ReturnLength = LocalReturnLength;
1409
1410 /* Setup the length and maximum length */
1411 FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
1412 ObjectNameInfo->Name.Length = (USHORT)FileLength -
1413 sizeof(OBJECT_NAME_INFORMATION);
1414 ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
1415 sizeof(UNICODE_NULL);
1416
1417 /* Free buffer and return */
1418 ExFreePoolWithTag(LocalInfo, TAG_IO);
1419 return Status;
1420 }
1421
1422 VOID
1423 NTAPI
1424 IopCloseFile(IN PEPROCESS Process OPTIONAL,
1425 IN PVOID ObjectBody,
1426 IN ACCESS_MASK GrantedAccess,
1427 IN ULONG HandleCount,
1428 IN ULONG SystemHandleCount)
1429 {
1430 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1431 KEVENT Event;
1432 PIRP Irp;
1433 PIO_STACK_LOCATION StackPtr;
1434 NTSTATUS Status;
1435 PDEVICE_OBJECT DeviceObject;
1436 KIRQL OldIrql;
1437 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1438
1439 /* If this isn't the last handle for the current process, quit */
1440 if (HandleCount != 1) return;
1441
1442 /* Check if the file is locked and has more then one handle opened */
1443 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
1444 {
1445 DPRINT1("We need to unlock this file!\n");
1446 ASSERT(FALSE);
1447 }
1448
1449 /* Make sure this is the last handle */
1450 if (SystemHandleCount != 1) return;
1451
1452 /* Check if this is a direct open or not */
1453 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1454 {
1455 /* Get the attached device */
1456 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1457 }
1458 else
1459 {
1460 /* Get the FO's device */
1461 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1462 }
1463
1464 /* Set the handle created flag */
1465 FileObject->Flags |= FO_HANDLE_CREATED;
1466
1467 /* Check if this is a sync FO and lock it */
1468 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopLockFileObject(FileObject);
1469
1470 /* Clear and set up Events */
1471 KeClearEvent(&FileObject->Event);
1472 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1473
1474 /* Allocate an IRP */
1475 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1476 if (!Irp) return;
1477
1478 /* Set it up */
1479 Irp->UserEvent = &Event;
1480 Irp->UserIosb = &Irp->IoStatus;
1481 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1482 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1483 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1484 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1485
1486 /* Set up Stack Pointer Data */
1487 StackPtr = IoGetNextIrpStackLocation(Irp);
1488 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
1489 StackPtr->FileObject = FileObject;
1490
1491 /* Queue the IRP */
1492 IopQueueIrpToThread(Irp);
1493
1494 /* Update operation counts */
1495 IopUpdateOperationCount(IopOtherTransfer);
1496
1497 /* Call the FS Driver */
1498 Status = IoCallDriver(DeviceObject, Irp);
1499 if (Status == STATUS_PENDING)
1500 {
1501 /* Wait for completion */
1502 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
1503 }
1504
1505 /* Unqueue the IRP */
1506 KeRaiseIrql(APC_LEVEL, &OldIrql);
1507 IopUnQueueIrpFromThread(Irp);
1508 KeLowerIrql(OldIrql);
1509
1510 /* Free the IRP */
1511 IoFreeIrp(Irp);
1512
1513 /* Release the lock if we were holding it */
1514 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
1515 }
1516
1517 NTSTATUS
1518 NTAPI
1519 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
1520 IN FILE_INFORMATION_CLASS FileInformationClass,
1521 IN ULONG FileInformationSize,
1522 OUT PVOID FileInformation)
1523 {
1524 NTSTATUS Status;
1525 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
1526 DUMMY_FILE_OBJECT DummyFileObject;
1527 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
1528 HANDLE Handle;
1529 OPEN_PACKET OpenPacket;
1530 BOOLEAN IsBasic;
1531 PAGED_CODE();
1532 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
1533
1534 /* Check if the caller was user mode */
1535 if (AccessMode != KernelMode)
1536 {
1537 /* Protect probe in SEH */
1538 _SEH2_TRY
1539 {
1540 /* Probe the buffer */
1541 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
1542 }
1543 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1544 {
1545 /* Return the exception code */
1546 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1547 }
1548 _SEH2_END;
1549 }
1550
1551 /* Check if this is a basic or full request */
1552 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
1553
1554 /* Setup the Open Packet */
1555 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
1556 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
1557 OpenPacket.Size = sizeof(OPEN_PACKET);
1558 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
1559 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
1560 OpenPacket.Disposition = FILE_OPEN;
1561 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
1562 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
1563 (AccessMode != KernelMode) ?
1564 &NetworkOpenInfo : FileInformation;
1565 OpenPacket.QueryOnly = TRUE;
1566 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
1567 OpenPacket.DummyFileObject = &DummyFileObject;
1568
1569 /* Update the operation count */
1570 IopUpdateOperationCount(IopOtherTransfer);
1571
1572 /*
1573 * Attempt opening the file. This will call the I/O Parse Routine for
1574 * the File Object (IopParseDevice) which will use the dummy file obejct
1575 * send the IRP to its device object. Note that we have two statuses
1576 * to worry about: the Object Manager's status (in Status) and the I/O
1577 * status, which is in the Open Packet's Final Status, and determined
1578 * by the Parse Check member.
1579 */
1580 Status = ObOpenObjectByName(ObjectAttributes,
1581 NULL,
1582 AccessMode,
1583 NULL,
1584 FILE_READ_ATTRIBUTES,
1585 &OpenPacket,
1586 &Handle);
1587 if (OpenPacket.ParseCheck != TRUE)
1588 {
1589 /* Parse failed */
1590 return Status;
1591 }
1592 else
1593 {
1594 /* Use the Io status */
1595 Status = OpenPacket.FinalStatus;
1596 }
1597
1598 /* Check if we were succesful and this was user mode and a full query */
1599 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
1600 {
1601 /* Enter SEH for copy */
1602 _SEH2_TRY
1603 {
1604 /* Copy the buffer back */
1605 RtlCopyMemory(FileInformation,
1606 &NetworkOpenInfo,
1607 FileInformationSize);
1608 }
1609 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1610 {
1611 /* Get exception code */
1612 Status = _SEH2_GetExceptionCode();
1613 }
1614 _SEH2_END;
1615 }
1616
1617 /* Return status */
1618 return Status;
1619 }
1620
1621 PVOID
1622 NTAPI
1623 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
1624 {
1625 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1626 {
1627 UNIMPLEMENTED;
1628 /* FIXME: return NULL for the moment ~ */
1629 return NULL;
1630 }
1631
1632 return NULL;
1633 }
1634
1635 NTSTATUS
1636 NTAPI
1637 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
1638 IN PVOID FilterContext,
1639 IN BOOLEAN Define)
1640 {
1641 if (!(FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION))
1642 {
1643 return STATUS_INVALID_PARAMETER;
1644 }
1645
1646 UNIMPLEMENTED;
1647
1648 return STATUS_NOT_IMPLEMENTED;
1649 }
1650
1651 /* FUNCTIONS *****************************************************************/
1652
1653 /*
1654 * @unimplemented
1655 */
1656 NTSTATUS
1657 NTAPI
1658 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
1659 IN ULONG Length,
1660 IN BOOLEAN SetOperation)
1661 {
1662 UNIMPLEMENTED;
1663 return STATUS_NOT_IMPLEMENTED;
1664 }
1665
1666 /*
1667 * @unimplemented
1668 */
1669 NTSTATUS
1670 NTAPI
1671 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
1672 IN ULONG QuotaLength,
1673 OUT PULONG ErrorOffset)
1674 {
1675 UNIMPLEMENTED;
1676 return STATUS_NOT_IMPLEMENTED;
1677 }
1678
1679 /*
1680 * @implemented
1681 */
1682 NTSTATUS
1683 NTAPI
1684 IoCreateFile(OUT PHANDLE FileHandle,
1685 IN ACCESS_MASK DesiredAccess,
1686 IN POBJECT_ATTRIBUTES ObjectAttributes,
1687 OUT PIO_STATUS_BLOCK IoStatusBlock,
1688 IN PLARGE_INTEGER AllocationSize OPTIONAL,
1689 IN ULONG FileAttributes,
1690 IN ULONG ShareAccess,
1691 IN ULONG Disposition,
1692 IN ULONG CreateOptions,
1693 IN PVOID EaBuffer OPTIONAL,
1694 IN ULONG EaLength,
1695 IN CREATE_FILE_TYPE CreateFileType,
1696 IN PVOID ExtraCreateParameters OPTIONAL,
1697 IN ULONG Options)
1698 {
1699 KPROCESSOR_MODE AccessMode;
1700 HANDLE LocalHandle = 0;
1701 LARGE_INTEGER SafeAllocationSize;
1702 PVOID SystemEaBuffer = NULL;
1703 NTSTATUS Status;
1704 OPEN_PACKET OpenPacket;
1705 ULONG EaErrorOffset;
1706
1707 PAGED_CODE();
1708 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
1709
1710 /* Check if we have no parameter checking to do */
1711 if (Options & IO_NO_PARAMETER_CHECKING)
1712 {
1713 /* Then force kernel-mode access to avoid checks */
1714 AccessMode = KernelMode;
1715 }
1716 else
1717 {
1718 /* Otherwise, use the actual mode */
1719 AccessMode = ExGetPreviousMode();
1720 }
1721
1722 /* Check if the call came from user mode */
1723 if (AccessMode != KernelMode)
1724 {
1725 _SEH2_TRY
1726 {
1727 ProbeForWriteHandle(FileHandle);
1728 ProbeForWriteIoStatusBlock(IoStatusBlock);
1729 if (AllocationSize)
1730 {
1731 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
1732 }
1733 else
1734 {
1735 SafeAllocationSize.QuadPart = 0;
1736 }
1737
1738 if ((EaBuffer) && (EaLength))
1739 {
1740 ProbeForRead(EaBuffer,
1741 EaLength,
1742 sizeof(ULONG));
1743
1744 /* marshal EaBuffer */
1745 SystemEaBuffer = ExAllocatePoolWithTag(NonPagedPool,
1746 EaLength,
1747 TAG_EA);
1748 if(!SystemEaBuffer)
1749 {
1750 _SEH2_YIELD(return STATUS_INSUFFICIENT_RESOURCES);
1751 }
1752
1753 RtlCopyMemory(SystemEaBuffer, EaBuffer, EaLength);
1754
1755 /* Validate the buffer */
1756 Status = IoCheckEaBufferValidity(SystemEaBuffer,
1757 EaLength,
1758 &EaErrorOffset);
1759 if (!NT_SUCCESS(Status))
1760 {
1761 DPRINT1("FIXME: IoCheckEaBufferValidity() failed with "
1762 "Status: %lx\n",Status);
1763
1764 /* Free EA Buffer and return the error */
1765 ExFreePoolWithTag(SystemEaBuffer, TAG_EA);
1766 _SEH2_YIELD(return Status);
1767 }
1768 }
1769 }
1770 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1771 {
1772 /* Free SystemEaBuffer if needed */
1773 if (SystemEaBuffer) ExFreePoolWithTag(SystemEaBuffer, TAG_EA);
1774
1775 /* Return the exception code */
1776 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1777 }
1778 _SEH2_END;
1779 }
1780 else
1781 {
1782 /* Check if this is a device attach */
1783 if (CreateOptions & IO_ATTACH_DEVICE_API)
1784 {
1785 /* Set the flag properly */
1786 Options |= IO_ATTACH_DEVICE;
1787 CreateOptions &= ~IO_ATTACH_DEVICE_API;
1788 }
1789
1790 /* Check if we have allocation size */
1791 if (AllocationSize)
1792 {
1793 /* Capture it */
1794 SafeAllocationSize = *AllocationSize;
1795 }
1796 else
1797 {
1798 /* Otherwise, no size */
1799 SafeAllocationSize.QuadPart = 0;
1800 }
1801
1802 /* Check if we have an EA packet */
1803 if ((EaBuffer) && (EaLength))
1804 {
1805 /* Allocate the kernel copy */
1806 SystemEaBuffer = ExAllocatePoolWithTag(NonPagedPool,
1807 EaLength,
1808 TAG_EA);
1809 if (!SystemEaBuffer) return STATUS_INSUFFICIENT_RESOURCES;
1810
1811 /* Copy the data */
1812 RtlCopyMemory(SystemEaBuffer, EaBuffer, EaLength);
1813
1814 /* Validate the buffer */
1815 Status = IoCheckEaBufferValidity(SystemEaBuffer,
1816 EaLength,
1817 &EaErrorOffset);
1818 if (!NT_SUCCESS(Status))
1819 {
1820 DPRINT1("FIXME: IoCheckEaBufferValidity() failed with "
1821 "Status: %lx\n",Status);
1822 }
1823 }
1824 }
1825
1826 /* Setup the Open Packet */
1827 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
1828 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
1829 OpenPacket.Size = sizeof(OPEN_PACKET);
1830 OpenPacket.OriginalAttributes = *ObjectAttributes;
1831 OpenPacket.AllocationSize = SafeAllocationSize;
1832 OpenPacket.CreateOptions = CreateOptions;
1833 OpenPacket.FileAttributes = (USHORT)FileAttributes;
1834 OpenPacket.ShareAccess = (USHORT)ShareAccess;
1835 OpenPacket.EaBuffer = SystemEaBuffer;
1836 OpenPacket.EaLength = EaLength;
1837 OpenPacket.Options = Options;
1838 OpenPacket.Disposition = Disposition;
1839 OpenPacket.CreateFileType = CreateFileType;
1840 OpenPacket.MailslotOrPipeParameters = ExtraCreateParameters;
1841
1842 /* Update the operation count */
1843 IopUpdateOperationCount(IopOtherTransfer);
1844
1845 /*
1846 * Attempt opening the file. This will call the I/O Parse Routine for
1847 * the File Object (IopParseDevice) which will create the object and
1848 * send the IRP to its device object. Note that we have two statuses
1849 * to worry about: the Object Manager's status (in Status) and the I/O
1850 * status, which is in the Open Packet's Final Status, and determined
1851 * by the Parse Check member.
1852 */
1853 Status = ObOpenObjectByName(ObjectAttributes,
1854 NULL,
1855 AccessMode,
1856 NULL,
1857 DesiredAccess,
1858 &OpenPacket,
1859 &LocalHandle);
1860
1861 /* Free the EA Buffer */
1862 if (OpenPacket.EaBuffer) ExFreePool(OpenPacket.EaBuffer);
1863
1864 /* Now check for Ob or Io failure */
1865 if (!(NT_SUCCESS(Status)) || (OpenPacket.ParseCheck != TRUE))
1866 {
1867 /* Check if Ob thinks well went well */
1868 if (NT_SUCCESS(Status))
1869 {
1870 /*
1871 * Tell it otherwise. Because we didn't use an ObjectType,
1872 * it incorrectly returned us a handle to God knows what.
1873 */
1874 ZwClose(LocalHandle);
1875 Status = STATUS_OBJECT_TYPE_MISMATCH;
1876 }
1877
1878 /* Now check the Io status */
1879 if (!NT_SUCCESS(OpenPacket.FinalStatus))
1880 {
1881 /* Use this status instead of Ob's */
1882 Status = OpenPacket.FinalStatus;
1883
1884 /* Check if it was only a warning */
1885 if (NT_WARNING(Status))
1886 {
1887 /* Protect write with SEH */
1888 _SEH2_TRY
1889 {
1890 /* In this case, we copy the I/O Status back */
1891 IoStatusBlock->Information = OpenPacket.Information;
1892 IoStatusBlock->Status = OpenPacket.FinalStatus;
1893 }
1894 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1895 {
1896 /* Get exception code */
1897 Status = _SEH2_GetExceptionCode();
1898 }
1899 _SEH2_END;
1900 }
1901 }
1902 else if ((OpenPacket.FileObject) && (OpenPacket.ParseCheck != 1))
1903 {
1904 /*
1905 * This can happen in the very bizarre case where the parse routine
1906 * actually executed more then once (due to a reparse) and ended
1907 * up failing after already having created the File Object.
1908 */
1909 if (OpenPacket.FileObject->FileName.Length)
1910 {
1911 /* It had a name, free it */
1912 ExFreePoolWithTag(OpenPacket.FileObject->FileName.Buffer, TAG_IO_NAME);
1913 }
1914
1915 /* Clear the device object to invalidate the FO, and dereference */
1916 OpenPacket.FileObject->DeviceObject = NULL;
1917 ObDereferenceObject(OpenPacket.FileObject);
1918 }
1919 }
1920 else
1921 {
1922 /* We reached success and have a valid file handle */
1923 OpenPacket.FileObject->Flags |= FO_HANDLE_CREATED;
1924
1925 /* Enter SEH for write back */
1926 _SEH2_TRY
1927 {
1928 /* Write back the handle and I/O Status */
1929 *FileHandle = LocalHandle;
1930 IoStatusBlock->Information = OpenPacket.Information;
1931 IoStatusBlock->Status = OpenPacket.FinalStatus;
1932
1933 /* Get the Io status */
1934 Status = OpenPacket.FinalStatus;
1935 }
1936 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1937 {
1938 /* Get the exception status */
1939 Status = _SEH2_GetExceptionCode();
1940 }
1941 _SEH2_END;
1942 }
1943
1944 /* Check if we were 100% successful */
1945 if ((OpenPacket.ParseCheck == TRUE) && (OpenPacket.FileObject))
1946 {
1947 /* Dereference the File Object */
1948 ObDereferenceObject(OpenPacket.FileObject);
1949 }
1950
1951 /* Return status */
1952 return Status;
1953 }
1954
1955 /*
1956 * @unimplemented
1957 */
1958 NTSTATUS
1959 NTAPI
1960 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
1961 IN ACCESS_MASK DesiredAccess,
1962 IN POBJECT_ATTRIBUTES ObjectAttributes,
1963 OUT PIO_STATUS_BLOCK IoStatusBlock,
1964 IN PLARGE_INTEGER AllocationSize OPTIONAL,
1965 IN ULONG FileAttributes,
1966 IN ULONG ShareAccess,
1967 IN ULONG Disposition,
1968 IN ULONG CreateOptions,
1969 IN PVOID EaBuffer OPTIONAL,
1970 IN ULONG EaLength,
1971 IN CREATE_FILE_TYPE CreateFileType,
1972 IN PVOID ExtraCreateParameters OPTIONAL,
1973 IN ULONG Options,
1974 IN PVOID DeviceObject)
1975 {
1976 UNIMPLEMENTED;
1977 return STATUS_NOT_IMPLEMENTED;
1978 }
1979
1980 /*
1981 * @implemented
1982 */
1983 PFILE_OBJECT
1984 NTAPI
1985 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
1986 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
1987 OUT PHANDLE FileObjectHandle OPTIONAL)
1988 {
1989 PFILE_OBJECT CreatedFileObject;
1990 NTSTATUS Status;
1991 HANDLE FileHandle;
1992 OBJECT_ATTRIBUTES ObjectAttributes;
1993 PAGED_CODE();
1994 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
1995
1996 /* Choose Device Object */
1997 if (FileObject) DeviceObject = FileObject->DeviceObject;
1998
1999 /* Reference the device object and initialize attributes */
2000 InterlockedIncrement(&DeviceObject->ReferenceCount);
2001 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2002
2003 /* Create the File Object */
2004 Status = ObCreateObject(KernelMode,
2005 IoFileObjectType,
2006 &ObjectAttributes,
2007 KernelMode,
2008 NULL,
2009 sizeof(FILE_OBJECT),
2010 sizeof(FILE_OBJECT),
2011 0,
2012 (PVOID*)&CreatedFileObject);
2013 if (!NT_SUCCESS(Status))
2014 {
2015 /* Fail */
2016 IopDereferenceDeviceObject(DeviceObject, FALSE);
2017 ExRaiseStatus(Status);
2018 }
2019
2020 /* Set File Object Data */
2021 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2022 CreatedFileObject->DeviceObject = DeviceObject;
2023 CreatedFileObject->Type = IO_TYPE_FILE;
2024 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2025 CreatedFileObject->Flags = FO_STREAM_FILE;
2026
2027 /* Initialize the wait event */
2028 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2029
2030 /* Insert it to create a handle for it */
2031 Status = ObInsertObject(CreatedFileObject,
2032 NULL,
2033 FILE_READ_DATA,
2034 1,
2035 (PVOID*)&CreatedFileObject,
2036 &FileHandle);
2037 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
2038
2039 /* Set the handle created flag */
2040 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2041 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2042
2043 /* Check if we have a VPB */
2044 if (DeviceObject->Vpb)
2045 {
2046 /* Reference it */
2047 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2048 }
2049
2050 /* Check if the caller wants the handle */
2051 if (FileObjectHandle)
2052 {
2053 /* Return it */
2054 *FileObjectHandle = FileHandle;
2055 ObDereferenceObject(CreatedFileObject);
2056 }
2057 else
2058 {
2059 /* Otherwise, close it */
2060 ObCloseHandle(FileHandle, KernelMode);
2061 }
2062
2063 /* Return the file object */
2064 return CreatedFileObject;
2065 }
2066
2067 /*
2068 * @implemented
2069 */
2070 PFILE_OBJECT
2071 NTAPI
2072 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
2073 IN PDEVICE_OBJECT DeviceObject)
2074 {
2075 /* Call the newer function */
2076 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
2077 }
2078
2079 /*
2080 * @implemented
2081 */
2082 PFILE_OBJECT
2083 NTAPI
2084 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
2085 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2086 {
2087 PFILE_OBJECT CreatedFileObject;
2088 NTSTATUS Status;
2089 OBJECT_ATTRIBUTES ObjectAttributes;
2090 PAGED_CODE();
2091 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2092
2093 /* Choose Device Object */
2094 if (FileObject) DeviceObject = FileObject->DeviceObject;
2095
2096 /* Reference the device object and initialize attributes */
2097 InterlockedIncrement(&DeviceObject->ReferenceCount);
2098 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2099
2100 /* Create the File Object */
2101 Status = ObCreateObject(KernelMode,
2102 IoFileObjectType,
2103 &ObjectAttributes,
2104 KernelMode,
2105 NULL,
2106 sizeof(FILE_OBJECT),
2107 sizeof(FILE_OBJECT),
2108 0,
2109 (PVOID*)&CreatedFileObject);
2110 if (!NT_SUCCESS(Status))
2111 {
2112 /* Fail */
2113 IopDereferenceDeviceObject(DeviceObject, FALSE);
2114 ExRaiseStatus(Status);
2115 }
2116
2117 /* Set File Object Data */
2118 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2119 CreatedFileObject->DeviceObject = DeviceObject;
2120 CreatedFileObject->Type = IO_TYPE_FILE;
2121 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2122 CreatedFileObject->Flags = FO_STREAM_FILE;
2123
2124 /* Initialize the wait event */
2125 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2126
2127 /* Destroy create information */
2128 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
2129 ObjectCreateInfo);
2130 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
2131
2132 /* Set the handle created flag */
2133 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2134 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2135
2136 /* Check if we have a VPB */
2137 if (DeviceObject->Vpb)
2138 {
2139 /* Reference it */
2140 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2141 }
2142
2143 /* Return the file object */
2144 return CreatedFileObject;
2145 }
2146
2147 /*
2148 * @implemented
2149 */
2150 PGENERIC_MAPPING
2151 NTAPI
2152 IoGetFileObjectGenericMapping(VOID)
2153 {
2154 /* Return the mapping */
2155 return &IopFileMapping;
2156 }
2157
2158 /*
2159 * @implemented
2160 */
2161 BOOLEAN
2162 NTAPI
2163 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
2164 {
2165 /* Return the flag status */
2166 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2167 }
2168
2169 /*
2170 * @implemented
2171 */
2172 BOOLEAN
2173 NTAPI
2174 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
2175 IN ACCESS_MASK DesiredAccess,
2176 IN ULONG OpenOptions,
2177 OUT PIO_STATUS_BLOCK IoStatus,
2178 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
2179 {
2180 NTSTATUS Status;
2181 DUMMY_FILE_OBJECT DummyFileObject;
2182 HANDLE Handle;
2183 OPEN_PACKET OpenPacket;
2184 PAGED_CODE();
2185 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2186
2187 /* Setup the Open Packet */
2188 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2189 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2190 OpenPacket.Size = sizeof(OPEN_PACKET);
2191 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
2192 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2193 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
2194 OpenPacket.Disposition = FILE_OPEN;
2195 OpenPacket.NetworkInformation = Buffer;
2196 OpenPacket.QueryOnly = TRUE;
2197 OpenPacket.FullAttributes = TRUE;
2198 OpenPacket.DummyFileObject = &DummyFileObject;
2199
2200 /*
2201 * Attempt opening the file. This will call the I/O Parse Routine for
2202 * the File Object (IopParseDevice) which will use the dummy file obejct
2203 * send the IRP to its device object. Note that we have two statuses
2204 * to worry about: the Object Manager's status (in Status) and the I/O
2205 * status, which is in the Open Packet's Final Status, and determined
2206 * by the Parse Check member.
2207 */
2208 Status = ObOpenObjectByName(ObjectAttributes,
2209 NULL,
2210 KernelMode,
2211 NULL,
2212 DesiredAccess,
2213 &OpenPacket,
2214 &Handle);
2215 if (OpenPacket.ParseCheck != TRUE)
2216 {
2217 /* Parse failed */
2218 IoStatus->Status = Status;
2219 }
2220 else
2221 {
2222 /* Use the Io status */
2223 IoStatus->Status = OpenPacket.FinalStatus;
2224 IoStatus->Information = OpenPacket.Information;
2225 }
2226
2227 /* Return success */
2228 return TRUE;
2229 }
2230
2231 /*
2232 * @implemented
2233 */
2234 VOID
2235 NTAPI
2236 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
2237 OUT PSHARE_ACCESS ShareAccess)
2238 {
2239 PAGED_CODE();
2240
2241 /* Check if the file has an extension */
2242 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2243 {
2244 /* Check if caller specified to ignore access checks */
2245 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2246 {
2247 /* Don't update share access */
2248 return;
2249 }
2250 }
2251
2252 /* Otherwise, check if there's any access present */
2253 if ((FileObject->ReadAccess) ||
2254 (FileObject->WriteAccess) ||
2255 (FileObject->DeleteAccess))
2256 {
2257 /* Increase the open count */
2258 ShareAccess->OpenCount++;
2259
2260 /* Add new share access */
2261 ShareAccess->Readers += FileObject->ReadAccess;
2262 ShareAccess->Writers += FileObject->WriteAccess;
2263 ShareAccess->Deleters += FileObject->DeleteAccess;
2264 ShareAccess->SharedRead += FileObject->SharedRead;
2265 ShareAccess->SharedWrite += FileObject->SharedWrite;
2266 ShareAccess->SharedDelete += FileObject->SharedDelete;
2267 }
2268 }
2269
2270 /*
2271 * @implemented
2272 */
2273 NTSTATUS
2274 NTAPI
2275 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
2276 IN ULONG DesiredShareAccess,
2277 IN PFILE_OBJECT FileObject,
2278 IN PSHARE_ACCESS ShareAccess,
2279 IN BOOLEAN Update)
2280 {
2281 BOOLEAN ReadAccess;
2282 BOOLEAN WriteAccess;
2283 BOOLEAN DeleteAccess;
2284 BOOLEAN SharedRead;
2285 BOOLEAN SharedWrite;
2286 BOOLEAN SharedDelete;
2287 PAGED_CODE();
2288
2289 /* Get access masks */
2290 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
2291 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
2292 DeleteAccess = (DesiredAccess & DELETE) != 0;
2293
2294 /* Set them in the file object */
2295 FileObject->ReadAccess = ReadAccess;
2296 FileObject->WriteAccess = WriteAccess;
2297 FileObject->DeleteAccess = DeleteAccess;
2298
2299 /* Check if the file has an extension */
2300 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2301 {
2302 /* Check if caller specified to ignore access checks */
2303 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2304 {
2305 /* Don't check share access */
2306 return STATUS_SUCCESS;
2307 }
2308 }
2309
2310 /* Check if we have any access */
2311 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
2312 {
2313 /* Get shared access masks */
2314 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
2315 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
2316 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
2317
2318 /* Set them */
2319 FileObject->SharedRead = SharedRead;
2320 FileObject->SharedWrite = SharedWrite;
2321 FileObject->SharedDelete = SharedDelete;
2322
2323 /* Check if the shared access is violated */
2324 if ((ReadAccess &&
2325 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
2326 (WriteAccess &&
2327 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
2328 (DeleteAccess &&
2329 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
2330 ((ShareAccess->Readers != 0) && !SharedRead) ||
2331 ((ShareAccess->Writers != 0) && !SharedWrite) ||
2332 ((ShareAccess->Deleters != 0) && !SharedDelete))
2333 {
2334 /* Sharing violation, fail */
2335 return STATUS_SHARING_VIOLATION;
2336 }
2337
2338 /* It's not, check if caller wants us to update it */
2339 if (Update)
2340 {
2341 /* Increase open count */
2342 ShareAccess->OpenCount++;
2343
2344 /* Update shared access */
2345 ShareAccess->Readers += ReadAccess;
2346 ShareAccess->Writers += WriteAccess;
2347 ShareAccess->Deleters += DeleteAccess;
2348 ShareAccess->SharedRead += SharedRead;
2349 ShareAccess->SharedWrite += SharedWrite;
2350 ShareAccess->SharedDelete += SharedDelete;
2351 }
2352 }
2353
2354 /* Validation successful */
2355 return STATUS_SUCCESS;
2356 }
2357
2358 /*
2359 * @implemented
2360 */
2361 VOID
2362 NTAPI
2363 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
2364 IN PSHARE_ACCESS ShareAccess)
2365 {
2366 PAGED_CODE();
2367
2368 /* Check if the file has an extension */
2369 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2370 {
2371 /* Check if caller specified to ignore access checks */
2372 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2373 {
2374 /* Don't update share access */
2375 return;
2376 }
2377 }
2378
2379 /* Otherwise, check if there's any access present */
2380 if ((FileObject->ReadAccess) ||
2381 (FileObject->WriteAccess) ||
2382 (FileObject->DeleteAccess))
2383 {
2384 /* Decrement the open count */
2385 ShareAccess->OpenCount--;
2386
2387 /* Remove share access */
2388 ShareAccess->Readers -= FileObject->ReadAccess;
2389 ShareAccess->Writers -= FileObject->WriteAccess;
2390 ShareAccess->Deleters -= FileObject->DeleteAccess;
2391 ShareAccess->SharedRead -= FileObject->SharedRead;
2392 ShareAccess->SharedWrite -= FileObject->SharedWrite;
2393 ShareAccess->SharedDelete -= FileObject->SharedDelete;
2394 }
2395 }
2396
2397 /*
2398 * @implemented
2399 */
2400 VOID
2401 NTAPI
2402 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
2403 IN ULONG DesiredShareAccess,
2404 IN PFILE_OBJECT FileObject,
2405 OUT PSHARE_ACCESS ShareAccess)
2406 {
2407 BOOLEAN ReadAccess;
2408 BOOLEAN WriteAccess;
2409 BOOLEAN DeleteAccess;
2410 BOOLEAN SharedRead;
2411 BOOLEAN SharedWrite;
2412 BOOLEAN SharedDelete;
2413 BOOLEAN Update = TRUE;
2414 PAGED_CODE();
2415
2416 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
2417 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
2418 DeleteAccess = (DesiredAccess & DELETE) != 0;
2419
2420 /* Check if the file has an extension */
2421 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2422 {
2423 /* Check if caller specified to ignore access checks */
2424 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2425 {
2426 /* Don't update share access */
2427 Update = FALSE;
2428 }
2429 }
2430
2431 /* Update basic access */
2432 FileObject->ReadAccess = ReadAccess;
2433 FileObject->WriteAccess = WriteAccess;
2434 FileObject->DeleteAccess = DeleteAccess;
2435
2436 /* Check if we have no access as all */
2437 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
2438 {
2439 /* Check if we need to update the structure */
2440 if (!Update) return;
2441
2442 /* Otherwise, clear data */
2443 ShareAccess->OpenCount = 0;
2444 ShareAccess->Readers = 0;
2445 ShareAccess->Writers = 0;
2446 ShareAccess->Deleters = 0;
2447 ShareAccess->SharedRead = 0;
2448 ShareAccess->SharedWrite = 0;
2449 ShareAccess->SharedDelete = 0;
2450 }
2451 else
2452 {
2453 /* Calculate shared access */
2454 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
2455 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
2456 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
2457
2458 /* Set it in the FO */
2459 FileObject->SharedRead = SharedRead;
2460 FileObject->SharedWrite = SharedWrite;
2461 FileObject->SharedDelete = SharedDelete;
2462
2463 /* Check if we need to update the structure */
2464 if (!Update) return;
2465
2466 /* Otherwise, set data */
2467 ShareAccess->OpenCount = 1;
2468 ShareAccess->Readers = ReadAccess;
2469 ShareAccess->Writers = WriteAccess;
2470 ShareAccess->Deleters = DeleteAccess;
2471 ShareAccess->SharedRead = SharedRead;
2472 ShareAccess->SharedWrite = SharedWrite;
2473 ShareAccess->SharedDelete = SharedDelete;
2474 }
2475 }
2476
2477 /*
2478 * @unimplemented
2479 */
2480 VOID
2481 NTAPI
2482 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
2483 IN PFILE_OBJECT FileObject)
2484 {
2485 UNIMPLEMENTED;
2486 }
2487
2488 /*
2489 * @unimplemented
2490 */
2491 NTSTATUS
2492 NTAPI
2493 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
2494 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
2495 {
2496 UNIMPLEMENTED;
2497 return STATUS_NOT_IMPLEMENTED;
2498 }
2499
2500 /*
2501 * @implemented
2502 */
2503 NTSTATUS
2504 NTAPI
2505 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
2506 IN BOOLEAN Remote)
2507 {
2508 NTSTATUS Status = STATUS_SUCCESS;
2509 BOOLEAN FlagSet;
2510
2511 /* Get the flag status */
2512 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2513
2514 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
2515 if (Remote && !FlagSet)
2516 {
2517 /* Set the flag */
2518 FileObject->Flags |= FO_REMOTE_ORIGIN;
2519 }
2520 else if (!Remote && FlagSet)
2521 {
2522 /* Remove the flag */
2523 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
2524 }
2525 else
2526 {
2527 /* Fail */
2528 Status = STATUS_INVALID_PARAMETER_MIX;
2529 }
2530
2531 /* Return status */
2532 return Status;
2533 }
2534
2535 /*
2536 * @implemented
2537 */
2538 NTSTATUS
2539 NTAPI
2540 NtCreateFile(PHANDLE FileHandle,
2541 ACCESS_MASK DesiredAccess,
2542 POBJECT_ATTRIBUTES ObjectAttributes,
2543 PIO_STATUS_BLOCK IoStatusBlock,
2544 PLARGE_INTEGER AllocateSize,
2545 ULONG FileAttributes,
2546 ULONG ShareAccess,
2547 ULONG CreateDisposition,
2548 ULONG CreateOptions,
2549 PVOID EaBuffer,
2550 ULONG EaLength)
2551 {
2552 /* Call the I/O Function */
2553 return IoCreateFile(FileHandle,
2554 DesiredAccess,
2555 ObjectAttributes,
2556 IoStatusBlock,
2557 AllocateSize,
2558 FileAttributes,
2559 ShareAccess,
2560 CreateDisposition,
2561 CreateOptions,
2562 EaBuffer,
2563 EaLength,
2564 CreateFileTypeNone,
2565 NULL,
2566 0);
2567 }
2568
2569 NTSTATUS
2570 NTAPI
2571 NtCreateMailslotFile(OUT PHANDLE FileHandle,
2572 IN ACCESS_MASK DesiredAccess,
2573 IN POBJECT_ATTRIBUTES ObjectAttributes,
2574 OUT PIO_STATUS_BLOCK IoStatusBlock,
2575 IN ULONG CreateOptions,
2576 IN ULONG MailslotQuota,
2577 IN ULONG MaxMessageSize,
2578 IN PLARGE_INTEGER TimeOut)
2579 {
2580 MAILSLOT_CREATE_PARAMETERS Buffer;
2581 PAGED_CODE();
2582
2583 /* Check for Timeout */
2584 if (TimeOut)
2585 {
2586 /* check if the call came from user mode */
2587 if (KeGetPreviousMode() != KernelMode)
2588 {
2589 /* Enter SEH for Probe */
2590 _SEH2_TRY
2591 {
2592 /* Probe the timeout */
2593 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
2594 }
2595 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2596 {
2597 /* Return the exception code */
2598 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2599 }
2600 _SEH2_END;
2601 }
2602 else
2603 {
2604 /* Otherwise, capture directly */
2605 Buffer.ReadTimeout = *TimeOut;
2606 }
2607
2608 /* Set the correct setting */
2609 Buffer.TimeoutSpecified = TRUE;
2610 }
2611 else
2612 {
2613 /* Tell the FSD we don't have a timeout */
2614 Buffer.TimeoutSpecified = FALSE;
2615 }
2616
2617 /* Set Settings */
2618 Buffer.MailslotQuota = MailslotQuota;
2619 Buffer.MaximumMessageSize = MaxMessageSize;
2620
2621 /* Call I/O */
2622 return IoCreateFile(FileHandle,
2623 DesiredAccess,
2624 ObjectAttributes,
2625 IoStatusBlock,
2626 NULL,
2627 0,
2628 FILE_SHARE_READ | FILE_SHARE_WRITE,
2629 FILE_CREATE,
2630 CreateOptions,
2631 NULL,
2632 0,
2633 CreateFileTypeMailslot,
2634 (PVOID)&Buffer,
2635 0);
2636 }
2637
2638 NTSTATUS
2639 NTAPI
2640 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
2641 IN ACCESS_MASK DesiredAccess,
2642 IN POBJECT_ATTRIBUTES ObjectAttributes,
2643 OUT PIO_STATUS_BLOCK IoStatusBlock,
2644 IN ULONG ShareAccess,
2645 IN ULONG CreateDisposition,
2646 IN ULONG CreateOptions,
2647 IN ULONG NamedPipeType,
2648 IN ULONG ReadMode,
2649 IN ULONG CompletionMode,
2650 IN ULONG MaximumInstances,
2651 IN ULONG InboundQuota,
2652 IN ULONG OutboundQuota,
2653 IN PLARGE_INTEGER DefaultTimeout)
2654 {
2655 NAMED_PIPE_CREATE_PARAMETERS Buffer;
2656 PAGED_CODE();
2657
2658 /* Check for Timeout */
2659 if (DefaultTimeout)
2660 {
2661 /* check if the call came from user mode */
2662 if (KeGetPreviousMode() != KernelMode)
2663 {
2664 /* Enter SEH for Probe */
2665 _SEH2_TRY
2666 {
2667 /* Probe the timeout */
2668 Buffer.DefaultTimeout =
2669 ProbeForReadLargeInteger(DefaultTimeout);
2670 }
2671 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2672 {
2673 /* Return the exception code */
2674 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2675 }
2676 _SEH2_END;
2677 }
2678 else
2679 {
2680 /* Otherwise, capture directly */
2681 Buffer.DefaultTimeout = *DefaultTimeout;
2682 }
2683
2684 /* Set the correct setting */
2685 Buffer.TimeoutSpecified = TRUE;
2686 }
2687 else
2688 {
2689 /* Tell the FSD we don't have a timeout */
2690 Buffer.TimeoutSpecified = FALSE;
2691 }
2692
2693 /* Set Settings */
2694 Buffer.NamedPipeType = NamedPipeType;
2695 Buffer.ReadMode = ReadMode;
2696 Buffer.CompletionMode = CompletionMode;
2697 Buffer.MaximumInstances = MaximumInstances;
2698 Buffer.InboundQuota = InboundQuota;
2699 Buffer.OutboundQuota = OutboundQuota;
2700
2701 /* Call I/O */
2702 return IoCreateFile(FileHandle,
2703 DesiredAccess,
2704 ObjectAttributes,
2705 IoStatusBlock,
2706 NULL,
2707 0,
2708 ShareAccess,
2709 CreateDisposition,
2710 CreateOptions,
2711 NULL,
2712 0,
2713 CreateFileTypeNamedPipe,
2714 (PVOID)&Buffer,
2715 0);
2716 }
2717
2718 NTSTATUS
2719 NTAPI
2720 NtFlushWriteBuffer(VOID)
2721 {
2722 PAGED_CODE();
2723
2724 /* Call the kernel */
2725 KeFlushWriteBuffer();
2726 return STATUS_SUCCESS;
2727 }
2728
2729 /*
2730 * @implemented
2731 */
2732 NTSTATUS
2733 NTAPI
2734 NtOpenFile(OUT PHANDLE FileHandle,
2735 IN ACCESS_MASK DesiredAccess,
2736 IN POBJECT_ATTRIBUTES ObjectAttributes,
2737 OUT PIO_STATUS_BLOCK IoStatusBlock,
2738 IN ULONG ShareAccess,
2739 IN ULONG OpenOptions)
2740 {
2741 /* Call the I/O Function */
2742 return IoCreateFile(FileHandle,
2743 DesiredAccess,
2744 ObjectAttributes,
2745 IoStatusBlock,
2746 NULL,
2747 0,
2748 ShareAccess,
2749 FILE_OPEN,
2750 OpenOptions,
2751 NULL,
2752 0,
2753 CreateFileTypeNone,
2754 NULL,
2755 0);
2756 }
2757
2758 NTSTATUS
2759 NTAPI
2760 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2761 OUT PFILE_BASIC_INFORMATION FileInformation)
2762 {
2763 /* Call the internal helper API */
2764 return IopQueryAttributesFile(ObjectAttributes,
2765 FileBasicInformation,
2766 sizeof(FILE_BASIC_INFORMATION),
2767 FileInformation);
2768 }
2769
2770 NTSTATUS
2771 NTAPI
2772 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2773 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
2774 {
2775 /* Call the internal helper API */
2776 return IopQueryAttributesFile(ObjectAttributes,
2777 FileNetworkOpenInformation,
2778 sizeof(FILE_NETWORK_OPEN_INFORMATION),
2779 FileInformation);
2780 }
2781
2782 /**
2783 * @name NtCancelIoFile
2784 *
2785 * Cancel all pending I/O operations in the current thread for specified
2786 * file object.
2787 *
2788 * @param FileHandle
2789 * Handle to file object to cancel requests for. No specific
2790 * access rights are needed.
2791 * @param IoStatusBlock
2792 * Pointer to status block which is filled with final completition
2793 * status on successful return.
2794 *
2795 * @return Status.
2796 *
2797 * @implemented
2798 */
2799 NTSTATUS
2800 NTAPI
2801 NtCancelIoFile(IN HANDLE FileHandle,
2802 OUT PIO_STATUS_BLOCK IoStatusBlock)
2803 {
2804 PFILE_OBJECT FileObject;
2805 PETHREAD Thread;
2806 PIRP Irp;
2807 KIRQL OldIrql;
2808 BOOLEAN OurIrpsInList = FALSE;
2809 LARGE_INTEGER Interval;
2810 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2811 NTSTATUS Status;
2812 PLIST_ENTRY ListHead, NextEntry;
2813 PAGED_CODE();
2814 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2815
2816 /* Check the previous mode */
2817 if (PreviousMode != KernelMode)
2818 {
2819 /* Enter SEH for probing */
2820 _SEH2_TRY
2821 {
2822 /* Probe the I/O Status Block */
2823 ProbeForWriteIoStatusBlock(IoStatusBlock);
2824 }
2825 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2826 {
2827 /* Return the exception code */
2828 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2829 }
2830 _SEH2_END;
2831 }
2832
2833 /* Reference the file object */
2834 Status = ObReferenceObjectByHandle(FileHandle,
2835 0,
2836 IoFileObjectType,
2837 PreviousMode,
2838 (PVOID*)&FileObject,
2839 NULL);
2840 if (!NT_SUCCESS(Status)) return Status;
2841
2842 /* IRP cancellations are synchronized at APC_LEVEL. */
2843 KeRaiseIrql(APC_LEVEL, &OldIrql);
2844
2845 /* Get the current thread */
2846 Thread = PsGetCurrentThread();
2847
2848 /* Update the operation counts */
2849 IopUpdateOperationCount(IopOtherTransfer);
2850
2851 /* Loop the list */
2852 ListHead = &Thread->IrpList;
2853 NextEntry = ListHead->Flink;
2854 while (ListHead != NextEntry)
2855 {
2856 /* Get the IRP and check if the File Object matches */
2857 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
2858 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
2859 {
2860 /* Cancel this IRP and keep looping */
2861 IoCancelIrp(Irp);
2862 OurIrpsInList = TRUE;
2863 }
2864
2865 /* Go to the next entry */
2866 NextEntry = NextEntry->Flink;
2867 }
2868
2869 /* Lower the IRQL */
2870 KeLowerIrql(OldIrql);
2871
2872 /* Check if we had found an IRP */
2873 if (OurIrpsInList)
2874 {
2875 /* Setup a 10ms wait */
2876 Interval.QuadPart = -100000;
2877
2878 /* Start looping */
2879 while (OurIrpsInList)
2880 {
2881 /* Do the wait */
2882 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
2883 OurIrpsInList = FALSE;
2884
2885 /* Raise IRQL */
2886 KeRaiseIrql(APC_LEVEL, &OldIrql);
2887
2888 /* Now loop the list again */
2889 NextEntry = ListHead->Flink;
2890 while (NextEntry != ListHead)
2891 {
2892 /* Get the IRP and check if the File Object matches */
2893 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
2894 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
2895 {
2896 /* Keep looping */
2897 OurIrpsInList = TRUE;
2898 break;
2899 }
2900
2901 /* Go to the next entry */
2902 NextEntry = NextEntry->Flink;
2903 }
2904
2905 /* Lower the IRQL */
2906 KeLowerIrql(OldIrql);
2907 }
2908 }
2909
2910 /* Enter SEH for writing back the I/O Status */
2911 _SEH2_TRY
2912 {
2913 /* Write success */
2914 IoStatusBlock->Status = STATUS_SUCCESS;
2915 IoStatusBlock->Information = 0;
2916 }
2917 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2918 {
2919 /* Ignore exception */
2920 }
2921 _SEH2_END;
2922
2923 /* Dereference the file object and return success */
2924 ObDereferenceObject(FileObject);
2925 return STATUS_SUCCESS;
2926 }
2927
2928 /*
2929 * @implemented
2930 */
2931 NTSTATUS
2932 NTAPI
2933 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
2934 {
2935 NTSTATUS Status;
2936 DUMMY_FILE_OBJECT DummyFileObject;
2937 HANDLE Handle;
2938 KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
2939 OPEN_PACKET OpenPacket;
2940 PAGED_CODE();
2941 IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
2942
2943 /* Setup the Open Packet */
2944 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2945 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2946 OpenPacket.Size = sizeof(OPEN_PACKET);
2947 OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
2948 OpenPacket.ShareAccess = FILE_SHARE_READ |
2949 FILE_SHARE_WRITE |
2950 FILE_SHARE_DELETE;
2951 OpenPacket.Disposition = FILE_OPEN;
2952 OpenPacket.DeleteOnly = TRUE;
2953 OpenPacket.DummyFileObject = &DummyFileObject;
2954
2955 /* Update the operation counts */
2956 IopUpdateOperationCount(IopOtherTransfer);
2957
2958 /*
2959 * Attempt opening the file. This will call the I/O Parse Routine for
2960 * the File Object (IopParseDevice) which will use the dummy file obejct
2961 * send the IRP to its device object. Note that we have two statuses
2962 * to worry about: the Object Manager's status (in Status) and the I/O
2963 * status, which is in the Open Packet's Final Status, and determined
2964 * by the Parse Check member.
2965 */
2966 Status = ObOpenObjectByName(ObjectAttributes,
2967 NULL,
2968 AccessMode,
2969 NULL,
2970 DELETE,
2971 &OpenPacket,
2972 &Handle);
2973 if (OpenPacket.ParseCheck != TRUE) return Status;
2974
2975 /* Retrn the Io status */
2976 return OpenPacket.FinalStatus;
2977 }
2978
2979 /* EOF */