[NTOS] Code formatting only.
[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/iomgr/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 * Pierre Schweitzer
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include <ntoskrnl.h>
16 #define NDEBUG
17 #include <debug.h>
18
19 extern ERESOURCE IopSecurityResource;
20
21 /* PRIVATE FUNCTIONS *********************************************************/
22
23 VOID
24 NTAPI
25 IopCheckBackupRestorePrivilege(IN PACCESS_STATE AccessState,
26 IN OUT PULONG CreateOptions,
27 IN KPROCESSOR_MODE PreviousMode,
28 IN ULONG Disposition)
29 {
30 ACCESS_MASK DesiredAccess, ReadAccess, WriteAccess;
31 PRIVILEGE_SET Privileges;
32 BOOLEAN AccessGranted, HaveBackupPriv = FALSE, CheckRestore = FALSE;
33 PAGED_CODE();
34
35 /* Don't do anything if privileges were checked already */
36 if (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED) return;
37
38 /* Check if the file was actually opened for backup purposes */
39 if (*CreateOptions & FILE_OPEN_FOR_BACKUP_INTENT)
40 {
41 /* Set the check flag since were doing it now */
42 AccessState->Flags |= SE_BACKUP_PRIVILEGES_CHECKED;
43
44 /* Set the access masks required */
45 ReadAccess = READ_CONTROL |
46 ACCESS_SYSTEM_SECURITY |
47 FILE_GENERIC_READ |
48 FILE_TRAVERSE;
49 WriteAccess = WRITE_DAC |
50 WRITE_OWNER |
51 ACCESS_SYSTEM_SECURITY |
52 FILE_GENERIC_WRITE |
53 FILE_ADD_FILE |
54 FILE_ADD_SUBDIRECTORY |
55 DELETE;
56 DesiredAccess = AccessState->RemainingDesiredAccess;
57
58 /* Check if desired access was the maximum */
59 if (DesiredAccess & MAXIMUM_ALLOWED)
60 {
61 /* Then add all the access masks required */
62 DesiredAccess |= (ReadAccess | WriteAccess);
63 }
64
65 /* Check if the file already exists */
66 if (Disposition & FILE_OPEN)
67 {
68 /* Check if desired access has the read mask */
69 if (ReadAccess & DesiredAccess)
70 {
71 /* Setup the privilege check lookup */
72 Privileges.PrivilegeCount = 1;
73 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
74 Privileges.Privilege[0].Luid = SeBackupPrivilege;
75 Privileges.Privilege[0].Attributes = 0;
76 AccessGranted = SePrivilegeCheck(&Privileges,
77 &AccessState->
78 SubjectSecurityContext,
79 PreviousMode);
80 if (AccessGranted)
81 {
82 /* Remember that backup was allowed */
83 HaveBackupPriv = TRUE;
84
85 /* Append the privileges and update the access state */
86 SeAppendPrivileges(AccessState, &Privileges);
87 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & ReadAccess);
88 AccessState->RemainingDesiredAccess &= ~ReadAccess;
89 DesiredAccess &= ~ReadAccess;
90
91 /* Set backup privilege for the token */
92 AccessState->Flags |= TOKEN_HAS_BACKUP_PRIVILEGE;
93 }
94 }
95 }
96 else
97 {
98 /* Caller is creating the file, check restore privileges later */
99 CheckRestore = TRUE;
100 }
101
102 /* Check if caller wants write access or if it's creating a file */
103 if ((WriteAccess & DesiredAccess) || (CheckRestore))
104 {
105 /* Setup the privilege lookup and do it */
106 Privileges.PrivilegeCount = 1;
107 Privileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
108 Privileges.Privilege[0].Luid = SeRestorePrivilege;
109 Privileges.Privilege[0].Attributes = 0;
110 AccessGranted = SePrivilegeCheck(&Privileges,
111 &AccessState->SubjectSecurityContext,
112 PreviousMode);
113 if (AccessGranted)
114 {
115 /* Remember that privilege was given */
116 HaveBackupPriv = TRUE;
117
118 /* Append the privileges and update the access state */
119 SeAppendPrivileges(AccessState, &Privileges);
120 AccessState->PreviouslyGrantedAccess |= (DesiredAccess & WriteAccess);
121 AccessState->RemainingDesiredAccess &= ~WriteAccess;
122
123 /* Set restore privilege for the token */
124 AccessState->Flags |= TOKEN_HAS_RESTORE_PRIVILEGE;
125 }
126 }
127
128 /* If we don't have the privilege, remove the option */
129 if (!HaveBackupPriv) *CreateOptions &= ~FILE_OPEN_FOR_BACKUP_INTENT;
130 }
131 }
132
133 NTSTATUS
134 NTAPI
135 IopCheckDeviceAndDriver(IN POPEN_PACKET OpenPacket,
136 IN PDEVICE_OBJECT DeviceObject)
137 {
138 /* Make sure the object is valid */
139 if ((IoGetDevObjExtension(DeviceObject)->ExtensionFlags &
140 (DOE_UNLOAD_PENDING |
141 DOE_DELETE_PENDING |
142 DOE_REMOVE_PENDING |
143 DOE_REMOVE_PROCESSED)) ||
144 (DeviceObject->Flags & DO_DEVICE_INITIALIZING))
145 {
146 /* It's unloading or initializing, so fail */
147 DPRINT1("You are seeing this because the following ROS driver: %wZ\n"
148 " sucks. Please fix it's AddDevice Routine\n",
149 &DeviceObject->DriverObject->DriverName);
150 return STATUS_NO_SUCH_DEVICE;
151 }
152 else if ((DeviceObject->Flags & DO_EXCLUSIVE) &&
153 (DeviceObject->ReferenceCount) &&
154 !(OpenPacket->RelatedFileObject) &&
155 !(OpenPacket->Options & IO_ATTACH_DEVICE))
156 {
157 return STATUS_ACCESS_DENIED;
158 }
159
160 else
161 {
162 /* Increase reference count */
163 InterlockedIncrement(&DeviceObject->ReferenceCount);
164 return STATUS_SUCCESS;
165 }
166 }
167
168 VOID
169 NTAPI
170 IopDoNameTransmogrify(IN PIRP Irp,
171 IN PFILE_OBJECT FileObject,
172 IN PREPARSE_DATA_BUFFER DataBuffer)
173 {
174 PWSTR Buffer;
175 USHORT Length;
176 USHORT RequiredLength;
177 PWSTR NewBuffer;
178
179 PAGED_CODE();
180
181 ASSERT(Irp->IoStatus.Status == STATUS_REPARSE);
182 ASSERT(Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT);
183 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
184 ASSERT(DataBuffer != NULL);
185 ASSERT(DataBuffer->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
186 ASSERT(DataBuffer->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
187 ASSERT(DataBuffer->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
188
189 /* First of all, validate data */
190 if (DataBuffer->ReparseDataLength < REPARSE_DATA_BUFFER_HEADER_SIZE ||
191 (DataBuffer->SymbolicLinkReparseBuffer.PrintNameLength +
192 DataBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +
193 FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0])) > MAXIMUM_REPARSE_DATA_BUFFER_SIZE)
194 {
195 Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
196 }
197
198 /* Everything went right */
199 if (NT_SUCCESS(Irp->IoStatus.Status))
200 {
201 /* Compute buffer & length */
202 Buffer = (PWSTR)((ULONG_PTR)DataBuffer->MountPointReparseBuffer.PathBuffer +
203 DataBuffer->MountPointReparseBuffer.SubstituteNameOffset);
204 Length = DataBuffer->MountPointReparseBuffer.SubstituteNameLength;
205
206 /* Check we don't overflow */
207 if (((ULONG)MAXUSHORT - DataBuffer->Reserved) <= (Length + sizeof(UNICODE_NULL)))
208 {
209 Irp->IoStatus.Status = STATUS_IO_REPARSE_DATA_INVALID;
210 }
211 else
212 {
213 /* Compute how much memory we'll need */
214 RequiredLength = DataBuffer->Reserved + Length + sizeof(UNICODE_NULL);
215
216 /* Check if FileObject can already hold what we need */
217 if (FileObject->FileName.MaximumLength >= RequiredLength)
218 {
219 NewBuffer = FileObject->FileName.Buffer;
220 }
221 else
222 {
223 /* Allocate otherwise */
224 NewBuffer = ExAllocatePoolWithTag(PagedPool, RequiredLength, TAG_IO_NAME);
225 if (NewBuffer == NULL)
226 {
227 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
228 }
229 }
230 }
231 }
232
233 /* Everything went right */
234 if (NT_SUCCESS(Irp->IoStatus.Status))
235 {
236 /* Copy the reserved data */
237 if (DataBuffer->Reserved)
238 {
239 RtlMoveMemory((PWSTR)((ULONG_PTR)NewBuffer + Length),
240 (PWSTR)((ULONG_PTR)FileObject->FileName.Buffer + FileObject->FileName.Length - DataBuffer->Reserved),
241 DataBuffer->Reserved);
242 }
243
244 /* Then the buffer */
245 if (Length)
246 {
247 RtlCopyMemory(NewBuffer, Buffer, Length);
248 }
249
250 /* And finally replace buffer if new one was allocated */
251 FileObject->FileName.Length = RequiredLength - sizeof(UNICODE_NULL);
252 if (NewBuffer != FileObject->FileName.Buffer)
253 {
254 if (FileObject->FileName.Buffer)
255 {
256 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
257 }
258
259 FileObject->FileName.Buffer = NewBuffer;
260 FileObject->FileName.MaximumLength = RequiredLength;
261 FileObject->FileName.Buffer[RequiredLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
262 }
263 }
264
265 /* We don't need them anymore - it was allocated by the driver */
266 ExFreePool(DataBuffer);
267 }
268
269 NTSTATUS
270 IopCheckTopDeviceHint(IN OUT PDEVICE_OBJECT * DeviceObject,
271 IN POPEN_PACKET OpenPacket,
272 BOOLEAN DirectOpen)
273 {
274 PDEVICE_OBJECT LocalDevice;
275 DEVICE_TYPE DeviceType;
276
277 LocalDevice = *DeviceObject;
278
279 /* Direct open is not allowed */
280 if (DirectOpen)
281 {
282 return STATUS_INVALID_PARAMETER;
283 }
284
285 /* Validate we have a file system device */
286 DeviceType = LocalDevice->DeviceType;
287 if (DeviceType != FILE_DEVICE_DISK_FILE_SYSTEM &&
288 DeviceType != FILE_DEVICE_CD_ROM_FILE_SYSTEM &&
289 DeviceType != FILE_DEVICE_TAPE_FILE_SYSTEM &&
290 DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM &&
291 DeviceType != FILE_DEVICE_DFS_FILE_SYSTEM)
292 {
293 return STATUS_INVALID_PARAMETER;
294 }
295
296 /* Verify the hint and if it's OK, return it */
297 if (IopVerifyDeviceObjectOnStack(LocalDevice, OpenPacket->TopDeviceObjectHint))
298 {
299 *DeviceObject = OpenPacket->TopDeviceObjectHint;
300 return STATUS_SUCCESS;
301 }
302
303 /* Failure case here */
304 /* If we thought was had come through a mount point,
305 * actually update we didn't and return the error
306 */
307 if (OpenPacket->TraversedMountPoint)
308 {
309 OpenPacket->TraversedMountPoint = FALSE;
310 return STATUS_MOUNT_POINT_NOT_RESOLVED;
311 }
312
313 /* Otherwise, just return the fact the hint is invalid */
314 return STATUS_INVALID_DEVICE_OBJECT_PARAMETER;
315 }
316
317 NTSTATUS
318 NTAPI
319 IopParseDevice(IN PVOID ParseObject,
320 IN PVOID ObjectType,
321 IN OUT PACCESS_STATE AccessState,
322 IN KPROCESSOR_MODE AccessMode,
323 IN ULONG Attributes,
324 IN OUT PUNICODE_STRING CompleteName,
325 IN OUT PUNICODE_STRING RemainingName,
326 IN OUT PVOID Context,
327 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
328 OUT PVOID *Object)
329 {
330 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
331 PDEVICE_OBJECT OriginalDeviceObject = (PDEVICE_OBJECT)ParseObject;
332 PDEVICE_OBJECT DeviceObject, OwnerDevice;
333 NTSTATUS Status;
334 PFILE_OBJECT FileObject;
335 PVPB Vpb = NULL;
336 PIRP Irp;
337 PIO_STACK_LOCATION StackLoc;
338 IO_SECURITY_CONTEXT SecurityContext;
339 IO_STATUS_BLOCK IoStatusBlock;
340 BOOLEAN DirectOpen = FALSE, OpenCancelled, UseDummyFile;
341 OBJECT_ATTRIBUTES ObjectAttributes;
342 KIRQL OldIrql;
343 PDUMMY_FILE_OBJECT LocalFileObject;
344 PFILE_BASIC_INFORMATION FileBasicInfo;
345 ULONG ReturnLength;
346 KPROCESSOR_MODE CheckMode;
347 BOOLEAN VolumeOpen = FALSE;
348 ACCESS_MASK DesiredAccess, GrantedAccess;
349 BOOLEAN AccessGranted, LockHeld = FALSE;
350 PPRIVILEGE_SET Privileges = NULL;
351 UNICODE_STRING FileString;
352 USHORT Attempt;
353 IOTRACE(IO_FILE_DEBUG, "ParseObject: %p. RemainingName: %wZ\n",
354 ParseObject, RemainingName);
355
356 for (Attempt = 0; Attempt < IOP_MAX_REPARSE_TRAVERSAL; ++Attempt)
357 {
358 /* Assume failure */
359 *Object = NULL;
360
361 /* Validate the open packet */
362 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
363
364 /* Valide reparse point in case we traversed a mountpoint */
365 if (OpenPacket->TraversedMountPoint)
366 {
367 /* This is a reparse point we understand */
368 ASSERT(OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT);
369
370 /* Make sure we're dealing with correct DO */
371 if (OriginalDeviceObject->DeviceType != FILE_DEVICE_DISK &&
372 OriginalDeviceObject->DeviceType != FILE_DEVICE_CD_ROM &&
373 OriginalDeviceObject->DeviceType != FILE_DEVICE_VIRTUAL_DISK &&
374 OriginalDeviceObject->DeviceType != FILE_DEVICE_TAPE)
375 {
376 OpenPacket->FinalStatus = STATUS_IO_REPARSE_DATA_INVALID;
377 return STATUS_IO_REPARSE_DATA_INVALID;
378 }
379 }
380
381 /* Check if we have a related file object */
382 if (OpenPacket->RelatedFileObject)
383 {
384 /* Use the related file object's device object */
385 OriginalDeviceObject = OpenPacket->RelatedFileObject->DeviceObject;
386 }
387
388 /* Validate device status */
389 Status = IopCheckDeviceAndDriver(OpenPacket, OriginalDeviceObject);
390 if (!NT_SUCCESS(Status))
391 {
392 /* We failed, return status */
393 OpenPacket->FinalStatus = Status;
394 return Status;
395 }
396
397 /* Map the generic mask and set the new mapping in the access state */
398 RtlMapGenericMask(&AccessState->RemainingDesiredAccess,
399 &IoFileObjectType->TypeInfo.GenericMapping);
400 RtlMapGenericMask(&AccessState->OriginalDesiredAccess,
401 &IoFileObjectType->TypeInfo.GenericMapping);
402 SeSetAccessStateGenericMapping(AccessState,
403 &IoFileObjectType->TypeInfo.GenericMapping);
404 DesiredAccess = AccessState->RemainingDesiredAccess;
405
406 /* Check what kind of access checks to do */
407 if ((AccessMode != KernelMode) ||
408 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK))
409 {
410 /* Call is from user-mode or kernel is forcing checks */
411 CheckMode = UserMode;
412 }
413 else
414 {
415 /* Call is from the kernel */
416 CheckMode = KernelMode;
417 }
418
419 /* Check privilege for backup or restore operation */
420 IopCheckBackupRestorePrivilege(AccessState,
421 &OpenPacket->CreateOptions,
422 CheckMode,
423 OpenPacket->Disposition);
424
425 /* Check if we are re-parsing */
426 if (((OpenPacket->Override) && !(RemainingName->Length)) ||
427 (AccessState->Flags & SE_BACKUP_PRIVILEGES_CHECKED))
428 {
429 /* Get granted access from the last call */
430 DesiredAccess |= AccessState->PreviouslyGrantedAccess;
431 }
432
433 /* Check if this is a volume open */
434 if ((OpenPacket->RelatedFileObject) &&
435 (OpenPacket->RelatedFileObject->Flags & FO_VOLUME_OPEN) &&
436 !(RemainingName->Length))
437 {
438 /* It is */
439 VolumeOpen = TRUE;
440 }
441
442 /* Now check if we need access checks */
443 if (((AccessMode != KernelMode) ||
444 (OpenPacket->Options & IO_FORCE_ACCESS_CHECK)) &&
445 (!(OpenPacket->RelatedFileObject) || (VolumeOpen)) &&
446 !(OpenPacket->Override))
447 {
448 KeEnterCriticalRegion();
449 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
450
451 /* Check if a device object is being parsed */
452 if (!RemainingName->Length)
453 {
454 /* Lock the subject context */
455 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
456 LockHeld = TRUE;
457
458 /* Do access check */
459 AccessGranted = SeAccessCheck(OriginalDeviceObject->
460 SecurityDescriptor,
461 &AccessState->SubjectSecurityContext,
462 LockHeld,
463 DesiredAccess,
464 0,
465 &Privileges,
466 &IoFileObjectType->
467 TypeInfo.GenericMapping,
468 UserMode,
469 &GrantedAccess,
470 &Status);
471 if (Privileges)
472 {
473 /* Append and free the privileges */
474 SeAppendPrivileges(AccessState, Privileges);
475 SeFreePrivileges(Privileges);
476 }
477
478 /* Check if we got access */
479 if (AccessGranted)
480 {
481 /* Update access state */
482 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
483 AccessState->RemainingDesiredAccess &= ~(GrantedAccess |
484 MAXIMUM_ALLOWED);
485 OpenPacket->Override= TRUE;
486 }
487
488 FileString.Length = 8;
489 FileString.MaximumLength = 8;
490 FileString.Buffer = L"File";
491
492 /* Do Audit/Alarm for open operation */
493 SeOpenObjectAuditAlarm(&FileString,
494 OriginalDeviceObject,
495 CompleteName,
496 OriginalDeviceObject->SecurityDescriptor,
497 AccessState,
498 FALSE,
499 AccessGranted,
500 UserMode,
501 &AccessState->GenerateOnClose);
502 }
503 else
504 {
505 /* Check if we need to do traverse validation */
506 if (!(AccessState->Flags & TOKEN_HAS_TRAVERSE_PRIVILEGE) ||
507 ((OriginalDeviceObject->DeviceType == FILE_DEVICE_DISK) ||
508 (OriginalDeviceObject->DeviceType == FILE_DEVICE_CD_ROM)))
509 {
510 /* Check if this is a restricted token */
511 if (!(AccessState->Flags & TOKEN_IS_RESTRICTED))
512 {
513 /* Do the FAST traverse check */
514 AccessGranted = SeFastTraverseCheck(OriginalDeviceObject->SecurityDescriptor,
515 AccessState,
516 FILE_TRAVERSE,
517 UserMode);
518 }
519 else
520 {
521 /* Fail */
522 AccessGranted = FALSE;
523 }
524
525 /* Check if we failed to get access */
526 if (!AccessGranted)
527 {
528 /* Lock the subject context */
529 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
530 LockHeld = TRUE;
531
532 /* Do access check */
533 AccessGranted = SeAccessCheck(OriginalDeviceObject->
534 SecurityDescriptor,
535 &AccessState->SubjectSecurityContext,
536 LockHeld,
537 FILE_TRAVERSE,
538 0,
539 &Privileges,
540 &IoFileObjectType->
541 TypeInfo.GenericMapping,
542 UserMode,
543 &GrantedAccess,
544 &Status);
545 if (Privileges)
546 {
547 /* Append and free the privileges */
548 SeAppendPrivileges(AccessState, Privileges);
549 SeFreePrivileges(Privileges);
550 }
551 }
552
553 /* FIXME: Do Audit/Alarm for traverse check */
554 }
555 else
556 {
557 /* Access automatically granted */
558 AccessGranted = TRUE;
559 }
560 }
561
562 ExReleaseResourceLite(&IopSecurityResource);
563 KeLeaveCriticalRegion();
564
565 /* Check if we hold the lock */
566 if (LockHeld)
567 {
568 /* Release it */
569 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
570 }
571
572 /* Check if access failed */
573 if (!AccessGranted)
574 {
575 /* Dereference the device and fail */
576 DPRINT1("Traverse access failed!\n");
577 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
578 return STATUS_ACCESS_DENIED;
579 }
580 }
581
582 /* Check if we can simply use a dummy file */
583 UseDummyFile = ((OpenPacket->QueryOnly) || (OpenPacket->DeleteOnly));
584
585 /* Check if this is a direct open */
586 if (!(RemainingName->Length) &&
587 !(OpenPacket->RelatedFileObject) &&
588 ((DesiredAccess & ~(SYNCHRONIZE |
589 FILE_READ_ATTRIBUTES |
590 READ_CONTROL |
591 ACCESS_SYSTEM_SECURITY |
592 WRITE_OWNER |
593 WRITE_DAC)) == 0) &&
594 !(UseDummyFile))
595 {
596 /* Remember this for later */
597 DirectOpen = TRUE;
598 }
599
600 /* Check if we have a related FO that wasn't a direct open */
601 if ((OpenPacket->RelatedFileObject) &&
602 !(OpenPacket->RelatedFileObject->Flags & FO_DIRECT_DEVICE_OPEN))
603 {
604 /* The device object is the one we were given */
605 DeviceObject = ParseObject;
606
607 /* Check if the related FO had a VPB */
608 if (OpenPacket->RelatedFileObject->Vpb)
609 {
610 /* Yes, remember it */
611 Vpb = OpenPacket->RelatedFileObject->Vpb;
612
613 /* Reference it */
614 InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
615
616 /* Check if we were given a specific top level device to use */
617 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
618 {
619 DeviceObject = Vpb->DeviceObject;
620 }
621 }
622 }
623 else
624 {
625 /* Check if it has a VPB */
626 if ((OriginalDeviceObject->Vpb) && !(DirectOpen))
627 {
628 /* Check if the VPB is mounted, and mount it */
629 Vpb = IopCheckVpbMounted(OpenPacket,
630 OriginalDeviceObject,
631 RemainingName,
632 &Status);
633 if (!Vpb) return Status;
634
635 /* Get the VPB's device object */
636 DeviceObject = Vpb->DeviceObject;
637 }
638 else
639 {
640 /* The device object is the one we were given */
641 DeviceObject = OriginalDeviceObject;
642 }
643
644 /* If we weren't given a specific top level device, look for an attached device */
645 if (!(OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT) &&
646 DeviceObject->AttachedDevice)
647 {
648 /* Get the attached device */
649 DeviceObject = IoGetAttachedDevice(DeviceObject);
650 }
651 }
652
653 /* If we have a top level device hint, verify it */
654 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
655 {
656 Status = IopCheckTopDeviceHint(&DeviceObject, OpenPacket, DirectOpen);
657 if (!NT_SUCCESS(Status))
658 {
659 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
660 if (Vpb) IopDereferenceVpbAndFree(Vpb);
661 return Status;
662 }
663 }
664
665 /* If we traversed a mount point, reset the information */
666 if (OpenPacket->TraversedMountPoint)
667 {
668 OpenPacket->TraversedMountPoint = FALSE;
669 }
670
671 /* Check if this is a secure FSD */
672 if ((DeviceObject->Characteristics & FILE_DEVICE_SECURE_OPEN) &&
673 ((OpenPacket->RelatedFileObject) || (RemainingName->Length)) &&
674 (!VolumeOpen))
675 {
676 Privileges = NULL;
677 GrantedAccess = 0;
678
679 KeEnterCriticalRegion();
680 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
681
682 /* Lock the subject context */
683 SeLockSubjectContext(&AccessState->SubjectSecurityContext);
684
685 /* Do access check */
686 AccessGranted = SeAccessCheck(OriginalDeviceObject->SecurityDescriptor,
687 &AccessState->SubjectSecurityContext,
688 TRUE,
689 DesiredAccess,
690 0,
691 &Privileges,
692 &IoFileObjectType->TypeInfo.GenericMapping,
693 UserMode,
694 &GrantedAccess,
695 &Status);
696 if (Privileges != NULL)
697 {
698 /* Append and free the privileges */
699 SeAppendPrivileges(AccessState, Privileges);
700 SeFreePrivileges(Privileges);
701 }
702
703 /* Check if we got access */
704 if (GrantedAccess)
705 {
706 AccessState->PreviouslyGrantedAccess |= GrantedAccess;
707 AccessState->RemainingDesiredAccess &= ~(GrantedAccess | MAXIMUM_ALLOWED);
708 }
709
710 FileString.Length = 8;
711 FileString.MaximumLength = 8;
712 FileString.Buffer = L"File";
713
714 /* Do Audit/Alarm for open operation
715 * NOTA: we audit target device object
716 */
717 SeOpenObjectAuditAlarm(&FileString,
718 DeviceObject,
719 CompleteName,
720 OriginalDeviceObject->SecurityDescriptor,
721 AccessState,
722 FALSE,
723 AccessGranted,
724 UserMode,
725 &AccessState->GenerateOnClose);
726
727 SeUnlockSubjectContext(&AccessState->SubjectSecurityContext);
728
729 ExReleaseResourceLite(&IopSecurityResource);
730 KeLeaveCriticalRegion();
731
732 /* Check if access failed */
733 if (!AccessGranted)
734 {
735 /* Dereference the device and fail */
736 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
737 if (Vpb) IopDereferenceVpbAndFree(Vpb);
738 return STATUS_ACCESS_DENIED;
739 }
740 }
741
742 /* Allocate the IRP */
743 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
744 if (!Irp)
745 {
746 /* Dereference the device and VPB, then fail */
747 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
748 if (Vpb) IopDereferenceVpbAndFree(Vpb);
749 return STATUS_INSUFFICIENT_RESOURCES;
750 }
751
752 /* Now set the IRP data */
753 Irp->RequestorMode = AccessMode;
754 Irp->Flags = IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API | IRP_DEFER_IO_COMPLETION;
755 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
756 Irp->UserIosb = &IoStatusBlock;
757 Irp->MdlAddress = NULL;
758 Irp->PendingReturned = FALSE;
759 Irp->UserEvent = NULL;
760 Irp->Cancel = FALSE;
761 Irp->CancelRoutine = NULL;
762 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
763
764 /* Setup the security context */
765 SecurityContext.SecurityQos = SecurityQos;
766 SecurityContext.AccessState = AccessState;
767 SecurityContext.DesiredAccess = AccessState->RemainingDesiredAccess;
768 SecurityContext.FullCreateOptions = OpenPacket->CreateOptions;
769
770 /* Get the I/O Stack location */
771 StackLoc = IoGetNextIrpStackLocation(Irp);
772 StackLoc->Control = 0;
773
774 /* Check what kind of file this is */
775 switch (OpenPacket->CreateFileType)
776 {
777 /* Normal file */
778 case CreateFileTypeNone:
779
780 /* Set the major function and EA Length */
781 StackLoc->MajorFunction = IRP_MJ_CREATE;
782 StackLoc->Parameters.Create.EaLength = OpenPacket->EaLength;
783
784 /* Set the flags */
785 StackLoc->Flags = (UCHAR)OpenPacket->Options;
786 StackLoc->Flags |= !(Attributes & OBJ_CASE_INSENSITIVE) ? SL_CASE_SENSITIVE: 0;
787 break;
788
789 /* Named pipe */
790 case CreateFileTypeNamedPipe:
791
792 /* Set the named pipe MJ and set the parameters */
793 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
794 StackLoc->Parameters.CreatePipe.Parameters = OpenPacket->ExtraCreateParameters;
795 break;
796
797 /* Mailslot */
798 case CreateFileTypeMailslot:
799
800 /* Set the mailslot MJ and set the parameters */
801 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
802 StackLoc->Parameters.CreateMailslot.Parameters = OpenPacket->ExtraCreateParameters;
803 break;
804 }
805
806 /* Set the common data */
807 Irp->Overlay.AllocationSize = OpenPacket->AllocationSize;
808 Irp->AssociatedIrp.SystemBuffer = OpenPacket->EaBuffer;
809 StackLoc->Parameters.Create.Options = (OpenPacket->Disposition << 24) |
810 (OpenPacket->CreateOptions &
811 0xFFFFFF);
812 StackLoc->Parameters.Create.FileAttributes = OpenPacket->FileAttributes;
813 StackLoc->Parameters.Create.ShareAccess = OpenPacket->ShareAccess;
814 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
815
816 /* Check if we really need to create an object */
817 if (!UseDummyFile)
818 {
819 ULONG ObjectSize = sizeof(FILE_OBJECT);
820
821 /* Tag on space for a file object extension */
822 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
823 ObjectSize += sizeof(FILE_OBJECT_EXTENSION);
824
825 /* Create the actual file object */
826 InitializeObjectAttributes(&ObjectAttributes,
827 NULL,
828 Attributes,
829 NULL,
830 NULL);
831 Status = ObCreateObject(KernelMode,
832 IoFileObjectType,
833 &ObjectAttributes,
834 AccessMode,
835 NULL,
836 ObjectSize,
837 0,
838 0,
839 (PVOID*)&FileObject);
840 if (!NT_SUCCESS(Status))
841 {
842 /* Create failed, free the IRP */
843 IoFreeIrp(Irp);
844
845 /* Dereference the device and VPB */
846 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
847 if (Vpb) IopDereferenceVpbAndFree(Vpb);
848
849 /* We failed, return status */
850 OpenPacket->FinalStatus = Status;
851 return Status;
852 }
853
854 /* Clear the file object */
855 RtlZeroMemory(FileObject, sizeof(FILE_OBJECT));
856
857 /* Check if this is Synch I/O */
858 if (OpenPacket->CreateOptions &
859 (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
860 {
861 /* Set the synch flag */
862 FileObject->Flags |= FO_SYNCHRONOUS_IO;
863
864 /* Check if it's also alertable */
865 if (OpenPacket->CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
866 {
867 /* It is, set the alertable flag */
868 FileObject->Flags |= FO_ALERTABLE_IO;
869 }
870 }
871
872 /* Check if this is synch I/O */
873 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
874 {
875 /* Initialize the event */
876 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, FALSE);
877 }
878
879 /* Check if the caller requested no intermediate buffering */
880 if (OpenPacket->CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
881 {
882 /* Set the correct flag for the FSD to read */
883 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
884 }
885
886 /* Check if the caller requested write through support */
887 if (OpenPacket->CreateOptions & FILE_WRITE_THROUGH)
888 {
889 /* Set the correct flag for the FSD to read */
890 FileObject->Flags |= FO_WRITE_THROUGH;
891 }
892
893 /* Check if the caller says the file will be only read sequentially */
894 if (OpenPacket->CreateOptions & FILE_SEQUENTIAL_ONLY)
895 {
896 /* Set the correct flag for the FSD to read */
897 FileObject->Flags |= FO_SEQUENTIAL_ONLY;
898 }
899
900 /* Check if the caller believes the file will be only read randomly */
901 if (OpenPacket->CreateOptions & FILE_RANDOM_ACCESS)
902 {
903 /* Set the correct flag for the FSD to read */
904 FileObject->Flags |= FO_RANDOM_ACCESS;
905 }
906
907 /* Check if we were asked to setup a file object extension */
908 if (OpenPacket->InternalFlags & IOP_CREATE_FILE_OBJECT_EXTENSION)
909 {
910 PFILE_OBJECT_EXTENSION FileObjectExtension;
911
912 /* Make sure the file object knows it has an extension */
913 FileObject->Flags |= FO_FILE_OBJECT_HAS_EXTENSION;
914
915 FileObjectExtension = (PFILE_OBJECT_EXTENSION)(FileObject + 1);
916 FileObject->FileObjectExtension = FileObjectExtension;
917
918 /* Add the top level device which we'll send the request to */
919 if (OpenPacket->InternalFlags & IOP_USE_TOP_LEVEL_DEVICE_HINT)
920 {
921 FileObjectExtension->TopDeviceObjectHint = DeviceObject;
922 }
923 }
924 }
925 else
926 {
927 /* Use the dummy object instead */
928 LocalFileObject = OpenPacket->LocalFileObject;
929 RtlZeroMemory(LocalFileObject, sizeof(DUMMY_FILE_OBJECT));
930
931 /* Set it up */
932 FileObject = (PFILE_OBJECT)&LocalFileObject->ObjectHeader.Body;
933 LocalFileObject->ObjectHeader.Type = IoFileObjectType;
934 LocalFileObject->ObjectHeader.PointerCount = 1;
935 }
936
937 /* Setup the file header */
938 FileObject->Type = IO_TYPE_FILE;
939 FileObject->Size = sizeof(FILE_OBJECT);
940 FileObject->RelatedFileObject = OpenPacket->RelatedFileObject;
941 FileObject->DeviceObject = OriginalDeviceObject;
942
943 /* Check if this is a direct device open */
944 if (DirectOpen) FileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
945
946 /* Check if the caller wants case sensitivity */
947 if (!(Attributes & OBJ_CASE_INSENSITIVE))
948 {
949 /* Tell the driver about it */
950 FileObject->Flags |= FO_OPENED_CASE_SENSITIVE;
951 }
952
953 /* Now set the file object */
954 Irp->Tail.Overlay.OriginalFileObject = FileObject;
955 StackLoc->FileObject = FileObject;
956
957 /* Check if the file object has a name */
958 if (RemainingName->Length)
959 {
960 /* Setup the unicode string */
961 FileObject->FileName.MaximumLength = RemainingName->Length + sizeof(WCHAR);
962 FileObject->FileName.Buffer = ExAllocatePoolWithTag(PagedPool,
963 FileObject->FileName.MaximumLength,
964 TAG_IO_NAME);
965 if (!FileObject->FileName.Buffer)
966 {
967 /* Failed to allocate the name, free the IRP */
968 IoFreeIrp(Irp);
969
970 /* Dereference the device object and VPB */
971 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
972 if (Vpb) IopDereferenceVpbAndFree(Vpb);
973
974 /* Clear the FO and dereference it */
975 FileObject->DeviceObject = NULL;
976 if (!UseDummyFile) ObDereferenceObject(FileObject);
977
978 /* Fail */
979 return STATUS_INSUFFICIENT_RESOURCES;
980 }
981 }
982
983 /* Copy the name */
984 RtlCopyUnicodeString(&FileObject->FileName, RemainingName);
985
986 /* Initialize the File Object event and set the FO */
987 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
988 OpenPacket->FileObject = FileObject;
989
990 /* Queue the IRP and call the driver */
991 IopQueueIrpToThread(Irp);
992 Status = IoCallDriver(DeviceObject, Irp);
993 if (Status == STATUS_PENDING)
994 {
995 /* Wait for the driver to complete the create */
996 KeWaitForSingleObject(&FileObject->Event,
997 Executive,
998 KernelMode,
999 FALSE,
1000 NULL);
1001
1002 /* Get the new status */
1003 Status = IoStatusBlock.Status;
1004 }
1005 else
1006 {
1007 /* We'll have to complete it ourselves */
1008 ASSERT(!Irp->PendingReturned);
1009 ASSERT(!Irp->MdlAddress);
1010
1011 /* Handle name change if required */
1012 if (Status == STATUS_REPARSE)
1013 {
1014 /* Check this is a mount point */
1015 if (Irp->IoStatus.Information == IO_REPARSE_TAG_MOUNT_POINT)
1016 {
1017 PREPARSE_DATA_BUFFER ReparseData;
1018
1019 /* Reparse point attributes were passed by the driver in the auxiliary buffer */
1020 ASSERT(Irp->Tail.Overlay.AuxiliaryBuffer != NULL);
1021 ReparseData = (PREPARSE_DATA_BUFFER)Irp->Tail.Overlay.AuxiliaryBuffer;
1022
1023 ASSERT(ReparseData->ReparseTag == IO_REPARSE_TAG_MOUNT_POINT);
1024 ASSERT(ReparseData->ReparseDataLength < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1025 ASSERT(ReparseData->Reserved < MAXIMUM_REPARSE_DATA_BUFFER_SIZE);
1026
1027 IopDoNameTransmogrify(Irp, FileObject, ReparseData);
1028 }
1029 }
1030
1031 /* Completion happens at APC_LEVEL */
1032 KeRaiseIrql(APC_LEVEL, &OldIrql);
1033
1034 /* Get the new I/O Status block ourselves */
1035 IoStatusBlock = Irp->IoStatus;
1036 Status = IoStatusBlock.Status;
1037
1038 /* Manually signal the even, we can't have any waiters */
1039 FileObject->Event.Header.SignalState = 1;
1040
1041 /* Now that we've signaled the events, de-associate the IRP */
1042 IopUnQueueIrpFromThread(Irp);
1043
1044 /* Check if the IRP had an input buffer */
1045 if ((Irp->Flags & IRP_BUFFERED_IO) &&
1046 (Irp->Flags & IRP_DEALLOCATE_BUFFER))
1047 {
1048 /* Free it. A driver might've tacked one on */
1049 ExFreePool(Irp->AssociatedIrp.SystemBuffer);
1050 }
1051
1052 /* Free the IRP and bring the IRQL back down */
1053 IoFreeIrp(Irp);
1054 KeLowerIrql(OldIrql);
1055 }
1056
1057 /* Copy the I/O Status */
1058 OpenPacket->Information = IoStatusBlock.Information;
1059
1060 /* The driver failed to create the file */
1061 if (!NT_SUCCESS(Status))
1062 {
1063 /* Check if we have a name */
1064 if (FileObject->FileName.Length)
1065 {
1066 /* Free it */
1067 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1068 FileObject->FileName.Length = 0;
1069 }
1070
1071 /* Clear its device object */
1072 FileObject->DeviceObject = NULL;
1073
1074 /* Save this now because the FO might go away */
1075 OpenCancelled = FileObject->Flags & FO_FILE_OPEN_CANCELLED ?
1076 TRUE : FALSE;
1077
1078 /* Clear the file object in the open packet */
1079 OpenPacket->FileObject = NULL;
1080
1081 /* Dereference the file object */
1082 if (!UseDummyFile) ObDereferenceObject(FileObject);
1083
1084 /* Dereference the device object */
1085 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1086
1087 /* Unless the driver cancelled the open, dereference the VPB */
1088 if (!(OpenCancelled) && (Vpb)) IopDereferenceVpbAndFree(Vpb);
1089
1090 /* Set the status and return */
1091 OpenPacket->FinalStatus = Status;
1092 return Status;
1093 }
1094 else if (Status == STATUS_REPARSE)
1095 {
1096 if (OpenPacket->Information == IO_REPARSE ||
1097 OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1098 {
1099 /* Update CompleteName with reparse info which got updated in IopDoNameTransmogrify() */
1100 if (CompleteName->MaximumLength < FileObject->FileName.Length)
1101 {
1102 PWSTR NewCompleteName;
1103
1104 /* Allocate a new buffer for the string */
1105 NewCompleteName = ExAllocatePoolWithTag(PagedPool, FileObject->FileName.Length, TAG_IO_NAME);
1106 if (NewCompleteName == NULL)
1107 {
1108 OpenPacket->FinalStatus = STATUS_INSUFFICIENT_RESOURCES;
1109 return STATUS_INSUFFICIENT_RESOURCES;
1110 }
1111
1112 /* Release the old one */
1113 if (CompleteName->Buffer != NULL)
1114 {
1115 ExFreePoolWithTag(CompleteName->Buffer, 0);
1116 }
1117
1118 /* And setup the new one */
1119 CompleteName->Buffer = NewCompleteName;
1120 CompleteName->MaximumLength = FileObject->FileName.Length;
1121 }
1122
1123 /* Copy our new complete name */
1124 RtlCopyUnicodeString(CompleteName, &FileObject->FileName);
1125
1126 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1127 {
1128 OpenPacket->RelatedFileObject = NULL;
1129 }
1130 }
1131
1132 /* Check if we have a name */
1133 if (FileObject->FileName.Length)
1134 {
1135 /* Free it */
1136 ExFreePoolWithTag(FileObject->FileName.Buffer, 0);
1137 FileObject->FileName.Length = 0;
1138 }
1139
1140 /* Clear its device object */
1141 FileObject->DeviceObject = NULL;
1142
1143 /* Clear the file object in the open packet */
1144 OpenPacket->FileObject = NULL;
1145
1146 /* Dereference the file object */
1147 if (!UseDummyFile) ObDereferenceObject(FileObject);
1148
1149 /* Dereference the device object */
1150 IopDereferenceDeviceObject(OriginalDeviceObject, FALSE);
1151
1152 /* Unless the driver cancelled the open, dereference the VPB */
1153 if (Vpb != NULL) IopDereferenceVpbAndFree(Vpb);
1154
1155 if (OpenPacket->Information != IO_REMOUNT)
1156 {
1157 OpenPacket->RelatedFileObject = NULL;
1158
1159 /* Inform we traversed a mount point for later attempt */
1160 if (OpenPacket->Information == IO_REPARSE_TAG_MOUNT_POINT)
1161 {
1162 OpenPacket->TraversedMountPoint = 1;
1163 }
1164
1165 /* In case we override checks, but got this on volume open, fail hard */
1166 if (OpenPacket->Override)
1167 {
1168 KeBugCheckEx(DRIVER_RETURNED_STATUS_REPARSE_FOR_VOLUME_OPEN,
1169 (ULONG_PTR)OriginalDeviceObject,
1170 (ULONG_PTR)DeviceObject,
1171 (ULONG_PTR)CompleteName,
1172 OpenPacket->Information);
1173 }
1174
1175 /* Return to IO/OB so that information can be upgraded */
1176 return STATUS_REPARSE;
1177 }
1178
1179 /* Loop again and reattempt an opening */
1180 continue;
1181 }
1182
1183 break;
1184 }
1185
1186 if (Attempt == IOP_MAX_REPARSE_TRAVERSAL)
1187 return STATUS_UNSUCCESSFUL;
1188
1189 /* Get the owner of the File Object */
1190 OwnerDevice = IoGetRelatedDeviceObject(FileObject);
1191
1192 /*
1193 * It's possible that the device to whom we sent the IRP to
1194 * isn't actually the device that ended opening the file object
1195 * internally.
1196 */
1197 if (OwnerDevice != DeviceObject)
1198 {
1199 /* We have to de-reference the VPB we had associated */
1200 if (Vpb) IopDereferenceVpbAndFree(Vpb);
1201
1202 /* And re-associate with the actual one */
1203 Vpb = FileObject->Vpb;
1204 if (Vpb) InterlockedIncrement((PLONG)&Vpb->ReferenceCount);
1205 }
1206
1207 /* Make sure we are not using a dummy */
1208 if (!UseDummyFile)
1209 {
1210 /* Check if this was a volume open */
1211 if ((!(FileObject->RelatedFileObject) ||
1212 (FileObject->RelatedFileObject->Flags & FO_VOLUME_OPEN)) &&
1213 !(FileObject->FileName.Length))
1214 {
1215 /* All signs point to it, but make sure it was actually an FSD */
1216 if ((OwnerDevice->DeviceType == FILE_DEVICE_DISK_FILE_SYSTEM) ||
1217 (OwnerDevice->DeviceType == FILE_DEVICE_CD_ROM_FILE_SYSTEM) ||
1218 (OwnerDevice->DeviceType == FILE_DEVICE_TAPE_FILE_SYSTEM) ||
1219 (OwnerDevice->DeviceType == FILE_DEVICE_FILE_SYSTEM))
1220 {
1221 /* The owner device is an FSD, so this is a volume open for real */
1222 FileObject->Flags |= FO_VOLUME_OPEN;
1223 }
1224 }
1225
1226 /* Reference the object and set the parse check */
1227 ObReferenceObject(FileObject);
1228 *Object = FileObject;
1229 OpenPacket->FinalStatus = IoStatusBlock.Status;
1230 OpenPacket->ParseCheck = TRUE;
1231 return OpenPacket->FinalStatus;
1232 }
1233 else
1234 {
1235 /* Check if this was a query */
1236 if (OpenPacket->QueryOnly)
1237 {
1238 /* Check if the caller wants basic info only */
1239 if (!OpenPacket->FullAttributes)
1240 {
1241 /* Allocate the buffer */
1242 FileBasicInfo = ExAllocatePoolWithTag(NonPagedPool,
1243 sizeof(*FileBasicInfo),
1244 TAG_IO);
1245 if (FileBasicInfo)
1246 {
1247 /* Do the query */
1248 Status = IoQueryFileInformation(FileObject,
1249 FileBasicInformation,
1250 sizeof(*FileBasicInfo),
1251 FileBasicInfo,
1252 &ReturnLength);
1253 if (NT_SUCCESS(Status))
1254 {
1255 /* Copy the data */
1256 RtlCopyMemory(OpenPacket->BasicInformation,
1257 FileBasicInfo,
1258 ReturnLength);
1259 }
1260
1261 /* Free our buffer */
1262 ExFreePoolWithTag(FileBasicInfo, TAG_IO);
1263 }
1264 else
1265 {
1266 /* Fail */
1267 Status = STATUS_INSUFFICIENT_RESOURCES;
1268 }
1269 }
1270 else
1271 {
1272 /* This is a full query */
1273 Status = IoQueryFileInformation(
1274 FileObject,
1275 FileNetworkOpenInformation,
1276 sizeof(FILE_NETWORK_OPEN_INFORMATION),
1277 OpenPacket->NetworkInformation,
1278 &ReturnLength);
1279 if (!NT_SUCCESS(Status)) ASSERT(Status != STATUS_NOT_IMPLEMENTED);
1280 }
1281 }
1282
1283 /* Delete the file object */
1284 IopDeleteFile(FileObject);
1285
1286 /* Clear out the file */
1287 OpenPacket->FileObject = NULL;
1288
1289 /* Set and return status */
1290 OpenPacket->FinalStatus = Status;
1291 OpenPacket->ParseCheck = TRUE;
1292 return Status;
1293 }
1294 }
1295
1296 NTSTATUS
1297 NTAPI
1298 IopParseFile(IN PVOID ParseObject,
1299 IN PVOID ObjectType,
1300 IN OUT PACCESS_STATE AccessState,
1301 IN KPROCESSOR_MODE AccessMode,
1302 IN ULONG Attributes,
1303 IN OUT PUNICODE_STRING CompleteName,
1304 IN OUT PUNICODE_STRING RemainingName,
1305 IN OUT PVOID Context OPTIONAL,
1306 IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
1307 OUT PVOID *Object)
1308 {
1309 PVOID DeviceObject;
1310 POPEN_PACKET OpenPacket = (POPEN_PACKET)Context;
1311
1312 /* Validate the open packet */
1313 if (!IopValidateOpenPacket(OpenPacket)) return STATUS_OBJECT_TYPE_MISMATCH;
1314
1315 /* Get the device object */
1316 DeviceObject = IoGetRelatedDeviceObject(ParseObject);
1317 OpenPacket->RelatedFileObject = ParseObject;
1318
1319 /* Call the main routine */
1320 return IopParseDevice(DeviceObject,
1321 ObjectType,
1322 AccessState,
1323 AccessMode,
1324 Attributes,
1325 CompleteName,
1326 RemainingName,
1327 OpenPacket,
1328 SecurityQos,
1329 Object);
1330 }
1331
1332 VOID
1333 NTAPI
1334 IopDeleteFile(IN PVOID ObjectBody)
1335 {
1336 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1337 PIRP Irp;
1338 PIO_STACK_LOCATION StackPtr;
1339 NTSTATUS Status;
1340 KEVENT Event;
1341 PDEVICE_OBJECT DeviceObject;
1342 BOOLEAN DereferenceDone = FALSE;
1343 PVPB Vpb;
1344 KIRQL OldIrql;
1345 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1346
1347 /* Check if the file has a device object */
1348 if (FileObject->DeviceObject)
1349 {
1350 /* Check if this is a direct open or not */
1351 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1352 {
1353 /* Get the attached device */
1354 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1355 }
1356 else
1357 {
1358 /* Use the file object's device object */
1359 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1360 }
1361
1362 /* Sanity check */
1363 ASSERT(!(FileObject->Flags & FO_SYNCHRONOUS_IO) ||
1364 (InterlockedExchange((PLONG)&FileObject->Busy, TRUE) == FALSE));
1365
1366 /* Check if the handle wasn't created yet */
1367 if (!(FileObject->Flags & FO_HANDLE_CREATED))
1368 {
1369 /* Send the cleanup IRP */
1370 IopCloseFile(NULL, ObjectBody, 0, 1, 1);
1371 }
1372
1373 /* Clear and set up Events */
1374 KeClearEvent(&FileObject->Event);
1375 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1376
1377 /* Allocate an IRP */
1378 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
1379
1380 /* Set it up */
1381 Irp->UserEvent = &Event;
1382 Irp->UserIosb = &Irp->IoStatus;
1383 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1384 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1385 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1386
1387 /* Set up Stack Pointer Data */
1388 StackPtr = IoGetNextIrpStackLocation(Irp);
1389 StackPtr->MajorFunction = IRP_MJ_CLOSE;
1390 StackPtr->FileObject = FileObject;
1391
1392 /* Queue the IRP */
1393 IopQueueIrpToThread(Irp);
1394
1395 /* Get the VPB and check if this isn't a direct open */
1396 Vpb = FileObject->Vpb;
1397 if ((Vpb) && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1398 {
1399 /* Dereference the VPB before the close */
1400 InterlockedDecrement((PLONG)&Vpb->ReferenceCount);
1401 }
1402
1403 /* Check if the FS will never disappear by itself */
1404 if (FileObject->DeviceObject->Flags & DO_NEVER_LAST_DEVICE)
1405 {
1406 /* Dereference it */
1407 InterlockedDecrement(&FileObject->DeviceObject->ReferenceCount);
1408 DereferenceDone = TRUE;
1409 }
1410
1411 /* Call the FS Driver */
1412 Status = IoCallDriver(DeviceObject, Irp);
1413 if (Status == STATUS_PENDING)
1414 {
1415 /* Wait for completion */
1416 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1417 }
1418
1419 /* De-queue the IRP */
1420 KeRaiseIrql(APC_LEVEL, &OldIrql);
1421 IopUnQueueIrpFromThread(Irp);
1422 KeLowerIrql(OldIrql);
1423
1424 /* Free the IRP */
1425 IoFreeIrp(Irp);
1426
1427 /* Clear the file name */
1428 if (FileObject->FileName.Buffer)
1429 {
1430 ExFreePoolWithTag(FileObject->FileName.Buffer, TAG_IO_NAME);
1431 FileObject->FileName.Buffer = NULL;
1432 }
1433
1434 /* Check if the FO had a completion port */
1435 if (FileObject->CompletionContext)
1436 {
1437 /* Free it */
1438 ObDereferenceObject(FileObject->CompletionContext->Port);
1439 ExFreePool(FileObject->CompletionContext);
1440 }
1441
1442 /* Check if the FO had extension */
1443 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
1444 {
1445 /* Release filter context structure if any */
1446 FsRtlPTeardownPerFileObjectContexts(FileObject);
1447 }
1448
1449 /* Check if dereference has been done yet */
1450 if (!DereferenceDone)
1451 {
1452 /* Dereference device object */
1453 IopDereferenceDeviceObject(FileObject->DeviceObject, FALSE);
1454 }
1455 }
1456 }
1457
1458 PDEVICE_OBJECT
1459 NTAPI
1460 IopGetDeviceAttachmentBase(IN PDEVICE_OBJECT DeviceObject)
1461 {
1462 PDEVICE_OBJECT PDO = DeviceObject;
1463
1464 /* Go down the stack to attempt to get the PDO */
1465 for (; ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo != NULL;
1466 PDO = ((PEXTENDED_DEVOBJ_EXTENSION)PDO->DeviceObjectExtension)->AttachedTo);
1467
1468 return PDO;
1469 }
1470
1471 PDEVICE_OBJECT
1472 NTAPI
1473 IopGetDevicePDO(IN PDEVICE_OBJECT DeviceObject)
1474 {
1475 KIRQL OldIrql;
1476 PDEVICE_OBJECT PDO;
1477
1478 ASSERT(DeviceObject != NULL);
1479
1480 OldIrql = KeAcquireQueuedSpinLock(LockQueueIoDatabaseLock);
1481 /* Get the base DO */
1482 PDO = IopGetDeviceAttachmentBase(DeviceObject);
1483 /* Check whether that's really a PDO and if so, keep it */
1484 if ((PDO->Flags & DO_BUS_ENUMERATED_DEVICE) != DO_BUS_ENUMERATED_DEVICE)
1485 {
1486 PDO = NULL;
1487 }
1488 else
1489 {
1490 ObReferenceObject(PDO);
1491 }
1492 KeReleaseQueuedSpinLock(LockQueueIoDatabaseLock, OldIrql);
1493
1494 return PDO;
1495 }
1496
1497 NTSTATUS
1498 NTAPI
1499 IopSetDeviceSecurityDescriptor(IN PDEVICE_OBJECT DeviceObject,
1500 IN PSECURITY_INFORMATION SecurityInformation,
1501 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1502 IN POOL_TYPE PoolType,
1503 IN PGENERIC_MAPPING GenericMapping)
1504 {
1505 NTSTATUS Status;
1506 PSECURITY_DESCRIPTOR OldSecurityDescriptor, CachedSecurityDescriptor, NewSecurityDescriptor;
1507
1508 PAGED_CODE();
1509
1510 /* Keep attempting till we find our old SD or fail */
1511 while (TRUE)
1512 {
1513 KeEnterCriticalRegion();
1514 ExAcquireResourceSharedLite(&IopSecurityResource, TRUE);
1515
1516 /* Get our old SD and reference it */
1517 OldSecurityDescriptor = DeviceObject->SecurityDescriptor;
1518 if (OldSecurityDescriptor != NULL)
1519 {
1520 ObReferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1521 }
1522
1523 ExReleaseResourceLite(&IopSecurityResource);
1524 KeLeaveCriticalRegion();
1525
1526 /* Set the SD information */
1527 NewSecurityDescriptor = OldSecurityDescriptor;
1528 Status = SeSetSecurityDescriptorInfo(NULL, SecurityInformation,
1529 SecurityDescriptor, &NewSecurityDescriptor,
1530 PoolType, GenericMapping);
1531
1532 if (!NT_SUCCESS(Status))
1533 {
1534 if (OldSecurityDescriptor != NULL)
1535 {
1536 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1537 }
1538
1539 break;
1540 }
1541
1542 /* Add the new DS to the internal cache */
1543 Status = ObLogSecurityDescriptor(NewSecurityDescriptor,
1544 &CachedSecurityDescriptor, 1);
1545 ExFreePool(NewSecurityDescriptor);
1546 if (!NT_SUCCESS(Status))
1547 {
1548 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1549 break;
1550 }
1551
1552 KeEnterCriticalRegion();
1553 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1554 /* Check if someone changed it in our back */
1555 if (DeviceObject->SecurityDescriptor == OldSecurityDescriptor)
1556 {
1557 /* We're clear, do the swap */
1558 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1559 ExReleaseResourceLite(&IopSecurityResource);
1560 KeLeaveCriticalRegion();
1561
1562 /* And dereference old SD (twice - us + not in use) */
1563 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 2);
1564
1565 break;
1566 }
1567 ExReleaseResourceLite(&IopSecurityResource);
1568 KeLeaveCriticalRegion();
1569
1570 /* If so, try again */
1571 ObDereferenceSecurityDescriptor(OldSecurityDescriptor, 1);
1572 ObDereferenceSecurityDescriptor(CachedSecurityDescriptor, 1);
1573 }
1574
1575 return Status;
1576 }
1577
1578 NTSTATUS
1579 NTAPI
1580 IopSetDeviceSecurityDescriptors(IN PDEVICE_OBJECT UpperDeviceObject,
1581 IN PDEVICE_OBJECT PhysicalDeviceObject,
1582 IN PSECURITY_INFORMATION SecurityInformation,
1583 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1584 IN POOL_TYPE PoolType,
1585 IN PGENERIC_MAPPING GenericMapping)
1586 {
1587 PDEVICE_OBJECT CurrentDO = PhysicalDeviceObject, NextDevice;
1588 NTSTATUS Status = STATUS_SUCCESS, TmpStatus;
1589
1590 PAGED_CODE();
1591
1592 ASSERT(PhysicalDeviceObject != NULL);
1593
1594 /* We always reference the DO we're working on */
1595 ObReferenceObject(CurrentDO);
1596
1597 /* Go up from PDO to latest DO */
1598 do
1599 {
1600 /* Attempt to set the new SD on it */
1601 TmpStatus = IopSetDeviceSecurityDescriptor(CurrentDO, SecurityInformation,
1602 SecurityDescriptor, PoolType,
1603 GenericMapping);
1604 /* Was our last one? Remember that status then */
1605 if (CurrentDO == UpperDeviceObject)
1606 {
1607 Status = TmpStatus;
1608 }
1609
1610 /* Try to move to the next DO (and thus, reference it) */
1611 NextDevice = CurrentDO->AttachedDevice;
1612 if (NextDevice)
1613 {
1614 ObReferenceObject(NextDevice);
1615 }
1616
1617 /* Dereference current DO and move to the next one */
1618 ObDereferenceObject(CurrentDO);
1619 CurrentDO = NextDevice;
1620 }
1621 while (CurrentDO != NULL);
1622
1623 return Status;
1624 }
1625
1626 NTSTATUS
1627 NTAPI
1628 IopGetSetSecurityObject(IN PVOID ObjectBody,
1629 IN SECURITY_OPERATION_CODE OperationCode,
1630 IN PSECURITY_INFORMATION SecurityInformation,
1631 IN PSECURITY_DESCRIPTOR SecurityDescriptor,
1632 IN OUT PULONG BufferLength,
1633 IN OUT PSECURITY_DESCRIPTOR *OldSecurityDescriptor,
1634 IN POOL_TYPE PoolType,
1635 IN OUT PGENERIC_MAPPING GenericMapping)
1636 {
1637 IO_STATUS_BLOCK IoStatusBlock;
1638 PIO_STACK_LOCATION StackPtr;
1639 PFILE_OBJECT FileObject;
1640 PDEVICE_OBJECT DeviceObject;
1641 PIRP Irp;
1642 BOOLEAN LocalEvent = FALSE;
1643 KEVENT Event;
1644 NTSTATUS Status = STATUS_SUCCESS;
1645 PAGED_CODE();
1646 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1647
1648 /* Check if this is a device or file */
1649 if (((PFILE_OBJECT)ObjectBody)->Type == IO_TYPE_DEVICE)
1650 {
1651 /* It's a device */
1652 DeviceObject = (PDEVICE_OBJECT)ObjectBody;
1653 FileObject = NULL;
1654 }
1655 else
1656 {
1657 /* It's a file */
1658 FileObject = (PFILE_OBJECT)ObjectBody;
1659
1660 /* Check if this is a direct open */
1661 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1662 {
1663 /* Get the Device Object */
1664 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1665 }
1666 else
1667 {
1668 /* Otherwise, use the direct device*/
1669 DeviceObject = FileObject->DeviceObject;
1670 }
1671 }
1672
1673 /* Check if the request was for a device object */
1674 if (!(FileObject) ||
1675 (!(FileObject->FileName.Length) && !(FileObject->RelatedFileObject)) ||
1676 (FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
1677 {
1678 /* Check what kind of request this was */
1679 if (OperationCode == QuerySecurityDescriptor)
1680 {
1681 return SeQuerySecurityDescriptorInfo(SecurityInformation,
1682 SecurityDescriptor,
1683 BufferLength,
1684 &DeviceObject->SecurityDescriptor);
1685 }
1686 else if (OperationCode == DeleteSecurityDescriptor)
1687 {
1688 /* Simply return success */
1689 return STATUS_SUCCESS;
1690 }
1691 else if (OperationCode == AssignSecurityDescriptor)
1692 {
1693 Status = STATUS_SUCCESS;
1694
1695 /* Make absolutely sure this is a device object */
1696 if (!(FileObject) || !(FileObject->Flags & FO_STREAM_FILE))
1697 {
1698 PSECURITY_DESCRIPTOR CachedSecurityDescriptor;
1699
1700 /* Add the security descriptor in cache */
1701 Status = ObLogSecurityDescriptor(SecurityDescriptor, &CachedSecurityDescriptor, 1);
1702 if (NT_SUCCESS(Status))
1703 {
1704 KeEnterCriticalRegion();
1705 ExAcquireResourceExclusiveLite(&IopSecurityResource, TRUE);
1706
1707 /* Assign the Security Descriptor */
1708 DeviceObject->SecurityDescriptor = CachedSecurityDescriptor;
1709
1710 ExReleaseResourceLite(&IopSecurityResource);
1711 KeLeaveCriticalRegion();
1712 }
1713 }
1714
1715 /* Return status */
1716 return Status;
1717 }
1718 else if (OperationCode == SetSecurityDescriptor)
1719 {
1720 /* Get the Physical Device Object if any */
1721 PDEVICE_OBJECT PDO = IopGetDevicePDO(DeviceObject);
1722
1723 if (PDO != NULL)
1724 {
1725 /* Apply the new SD to any DO in the path from PDO to current DO */
1726 Status = IopSetDeviceSecurityDescriptors(DeviceObject, PDO,
1727 SecurityInformation,
1728 SecurityDescriptor,
1729 PoolType, GenericMapping);
1730 ObDereferenceObject(PDO);
1731 }
1732 else
1733 {
1734 /* Otherwise, just set for ourselves */
1735 Status = IopSetDeviceSecurityDescriptor(DeviceObject,
1736 SecurityInformation,
1737 SecurityDescriptor,
1738 PoolType, GenericMapping);
1739 }
1740
1741 return STATUS_SUCCESS;
1742 }
1743
1744 /* Shouldn't happen */
1745 return STATUS_SUCCESS;
1746 }
1747 else if (OperationCode == DeleteSecurityDescriptor)
1748 {
1749 /* Same as for devices, do nothing */
1750 return STATUS_SUCCESS;
1751 }
1752
1753 /* At this point, we know we're a file. Reference it */
1754 ObReferenceObject(FileObject);
1755
1756 /* Check if we should use Sync IO or not */
1757 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1758 {
1759 /* Lock the file object */
1760 Status = IopLockFileObject(FileObject, ExGetPreviousMode());
1761 if (Status != STATUS_SUCCESS)
1762 {
1763 ObDereferenceObject(FileObject);
1764 return Status;
1765 }
1766 }
1767 else
1768 {
1769 /* Use local event */
1770 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1771 LocalEvent = TRUE;
1772 }
1773
1774 /* Clear the File Object event */
1775 KeClearEvent(&FileObject->Event);
1776
1777 /* Get the device object */
1778 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1779
1780 /* Allocate the IRP */
1781 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1782 if (!Irp) return IopCleanupFailedIrp(FileObject, NULL, NULL);
1783
1784 /* Set the IRP */
1785 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1786 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1787 Irp->RequestorMode = ExGetPreviousMode();
1788 Irp->UserIosb = &IoStatusBlock;
1789 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1790 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1791 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1792
1793 /* Set Stack Parameters */
1794 StackPtr = IoGetNextIrpStackLocation(Irp);
1795 StackPtr->FileObject = FileObject;
1796
1797 /* Check if this is a query or set */
1798 if (OperationCode == QuerySecurityDescriptor)
1799 {
1800 /* Set the major function and parameters */
1801 StackPtr->MajorFunction = IRP_MJ_QUERY_SECURITY;
1802 StackPtr->Parameters.QuerySecurity.SecurityInformation =
1803 *SecurityInformation;
1804 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
1805 Irp->UserBuffer = SecurityDescriptor;
1806 }
1807 else
1808 {
1809 /* Set the major function and parameters for a set */
1810 StackPtr->MajorFunction = IRP_MJ_SET_SECURITY;
1811 StackPtr->Parameters.SetSecurity.SecurityInformation =
1812 *SecurityInformation;
1813 StackPtr->Parameters.SetSecurity.SecurityDescriptor =
1814 SecurityDescriptor;
1815 }
1816
1817 /* Queue the IRP */
1818 IopQueueIrpToThread(Irp);
1819
1820 /* Update operation counts */
1821 IopUpdateOperationCount(IopOtherTransfer);
1822
1823 /* Call the Driver */
1824 Status = IoCallDriver(DeviceObject, Irp);
1825
1826 /* Check if this was async I/O */
1827 if (LocalEvent)
1828 {
1829 /* Check if the IRP is pending completion */
1830 if (Status == STATUS_PENDING)
1831 {
1832 /* Wait on the local event */
1833 KeWaitForSingleObject(&Event,
1834 Executive,
1835 KernelMode,
1836 FALSE,
1837 NULL);
1838 Status = IoStatusBlock.Status;
1839 }
1840 }
1841 else
1842 {
1843 /* Check if the IRP is pending completion */
1844 if (Status == STATUS_PENDING)
1845 {
1846 /* Wait on the file object */
1847 KeWaitForSingleObject(&FileObject->Event,
1848 Executive,
1849 KernelMode,
1850 FALSE,
1851 NULL);
1852 Status = FileObject->FinalStatus;
1853 }
1854
1855 /* Release the lock */
1856 IopUnlockFileObject(FileObject);
1857 }
1858
1859 /* This Driver doesn't implement Security, so try to give it a default */
1860 if (Status == STATUS_INVALID_DEVICE_REQUEST)
1861 {
1862 /* Was this a query? */
1863 if (OperationCode == QuerySecurityDescriptor)
1864 {
1865 /* Set a World Security Descriptor */
1866 Status = SeSetWorldSecurityDescriptor(*SecurityInformation,
1867 SecurityDescriptor,
1868 BufferLength);
1869 }
1870 else
1871 {
1872 /* It wasn't a query, so just fake success */
1873 Status = STATUS_SUCCESS;
1874 }
1875 }
1876 else if (OperationCode == QuerySecurityDescriptor)
1877 {
1878 /* Callers usually expect the normalized form */
1879 if (Status == STATUS_BUFFER_OVERFLOW) Status = STATUS_BUFFER_TOO_SMALL;
1880
1881 _SEH2_TRY
1882 {
1883 /* Return length */
1884 *BufferLength = (ULONG)IoStatusBlock.Information;
1885 }
1886 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1887 {
1888 /* Get the exception code */
1889 Status = _SEH2_GetExceptionCode();
1890 }
1891 _SEH2_END;
1892 }
1893
1894 /* Return Status */
1895 return Status;
1896 }
1897
1898 NTSTATUS
1899 NTAPI
1900 IopQueryName(IN PVOID ObjectBody,
1901 IN BOOLEAN HasName,
1902 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1903 IN ULONG Length,
1904 OUT PULONG ReturnLength,
1905 IN KPROCESSOR_MODE PreviousMode)
1906 {
1907 return IopQueryNameInternal(ObjectBody,
1908 HasName,
1909 FALSE,
1910 ObjectNameInfo,
1911 Length,
1912 ReturnLength,
1913 PreviousMode);
1914 }
1915
1916 NTSTATUS
1917 NTAPI
1918 IopQueryNameInternal(IN PVOID ObjectBody,
1919 IN BOOLEAN HasName,
1920 IN BOOLEAN QueryDosName,
1921 OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
1922 IN ULONG Length,
1923 OUT PULONG ReturnLength,
1924 IN KPROCESSOR_MODE PreviousMode)
1925 {
1926 POBJECT_NAME_INFORMATION LocalInfo;
1927 PFILE_NAME_INFORMATION LocalFileInfo;
1928 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
1929 ULONG LocalReturnLength, FileLength;
1930 BOOLEAN LengthMismatch = FALSE;
1931 NTSTATUS Status;
1932 PWCHAR p;
1933 PDEVICE_OBJECT DeviceObject;
1934 BOOLEAN NoObCall;
1935
1936 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1937
1938 /* Validate length */
1939 if (Length < sizeof(OBJECT_NAME_INFORMATION))
1940 {
1941 /* Wrong length, fail */
1942 *ReturnLength = sizeof(OBJECT_NAME_INFORMATION);
1943 return STATUS_INFO_LENGTH_MISMATCH;
1944 }
1945
1946 /* Allocate Buffer */
1947 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, TAG_IO);
1948 if (!LocalInfo) return STATUS_INSUFFICIENT_RESOURCES;
1949
1950 /* Query DOS name if the caller asked to */
1951 NoObCall = FALSE;
1952 if (QueryDosName)
1953 {
1954 DeviceObject = FileObject->DeviceObject;
1955
1956 /* In case of a network file system, don't call mountmgr */
1957 if (DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM)
1958 {
1959 /* We'll store separator and terminator */
1960 LocalReturnLength = sizeof(OBJECT_NAME_INFORMATION) + 2 * sizeof(WCHAR);
1961 if (Length < LocalReturnLength)
1962 {
1963 Status = STATUS_BUFFER_OVERFLOW;
1964 }
1965 else
1966 {
1967 LocalInfo->Name.Length = sizeof(WCHAR);
1968 LocalInfo->Name.MaximumLength = sizeof(WCHAR);
1969 LocalInfo->Name.Buffer = (PVOID)((ULONG_PTR)LocalInfo + sizeof(OBJECT_NAME_INFORMATION));
1970 LocalInfo->Name.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
1971 Status = STATUS_SUCCESS;
1972 }
1973 }
1974 /* Otherwise, call mountmgr to get DOS name */
1975 else
1976 {
1977 Status = IoVolumeDeviceToDosName(DeviceObject, &LocalInfo->Name);
1978 LocalReturnLength = LocalInfo->Name.Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
1979 }
1980 }
1981
1982 /* Fall back if querying DOS name failed or if caller never wanted it ;-) */
1983 if (!QueryDosName || !NT_SUCCESS(Status))
1984 {
1985 /* Query the name */
1986 Status = ObQueryNameString(FileObject->DeviceObject,
1987 LocalInfo,
1988 Length,
1989 &LocalReturnLength);
1990 }
1991 else
1992 {
1993 NoObCall = TRUE;
1994 }
1995
1996 if (!NT_SUCCESS(Status) && (Status != STATUS_INFO_LENGTH_MISMATCH))
1997 {
1998 /* Free the buffer and fail */
1999 ExFreePoolWithTag(LocalInfo, TAG_IO);
2000 return Status;
2001 }
2002
2003 /* Get buffer pointer */
2004 p = (PWCHAR)(ObjectNameInfo + 1);
2005
2006 _SEH2_TRY
2007 {
2008 /* Copy the information */
2009 if (QueryDosName && NoObCall)
2010 {
2011 ASSERT(PreviousMode == KernelMode);
2012
2013 /* Copy structure first */
2014 RtlCopyMemory(ObjectNameInfo,
2015 LocalInfo,
2016 (Length >= LocalReturnLength ? sizeof(OBJECT_NAME_INFORMATION) : Length));
2017 /* Name then */
2018 RtlCopyMemory(p, LocalInfo->Name.Buffer,
2019 (Length >= LocalReturnLength ? LocalInfo->Name.Length : Length - sizeof(OBJECT_NAME_INFORMATION)));
2020
2021 if (FileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM)
2022 {
2023 ExFreePool(LocalInfo->Name.Buffer);
2024 }
2025 }
2026 else
2027 {
2028 RtlCopyMemory(ObjectNameInfo,
2029 LocalInfo,
2030 (LocalReturnLength > Length) ?
2031 Length : LocalReturnLength);
2032 }
2033
2034 /* Set buffer pointer */
2035 ObjectNameInfo->Name.Buffer = p;
2036
2037 /* Advance in buffer */
2038 p += (LocalInfo->Name.Length / sizeof(WCHAR));
2039
2040 /* Check if this already filled our buffer */
2041 if (LocalReturnLength > Length)
2042 {
2043 /* Set the length mismatch to true, so that we can return
2044 * the proper buffer size to the caller later
2045 */
2046 LengthMismatch = TRUE;
2047
2048 /* Save the initial buffer length value */
2049 *ReturnLength = LocalReturnLength;
2050 }
2051
2052 /* Now get the file name buffer and check the length needed */
2053 LocalFileInfo = (PFILE_NAME_INFORMATION)LocalInfo;
2054 FileLength = Length -
2055 LocalReturnLength +
2056 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2057
2058 /* Query the File name */
2059 if (PreviousMode == KernelMode &&
2060 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2061 {
2062 Status = IopGetFileInformation(FileObject,
2063 LengthMismatch ? Length : FileLength,
2064 FileNameInformation,
2065 LocalFileInfo,
2066 &LocalReturnLength);
2067 }
2068 else
2069 {
2070 Status = IoQueryFileInformation(FileObject,
2071 FileNameInformation,
2072 LengthMismatch ? Length : FileLength,
2073 LocalFileInfo,
2074 &LocalReturnLength);
2075 }
2076 if (NT_ERROR(Status))
2077 {
2078 /* Allow status that would mean it's not implemented in the storage stack */
2079 if (Status != STATUS_INVALID_PARAMETER && Status != STATUS_INVALID_DEVICE_REQUEST &&
2080 Status != STATUS_NOT_IMPLEMENTED && Status != STATUS_INVALID_INFO_CLASS)
2081 {
2082 _SEH2_LEAVE;
2083 }
2084
2085 /* In such case, zero output */
2086 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2087 LocalFileInfo->FileNameLength = 0;
2088 LocalFileInfo->FileName[0] = OBJ_NAME_PATH_SEPARATOR;
2089 }
2090 else
2091 {
2092 /* We'll at least return the name length */
2093 if (LocalReturnLength < FIELD_OFFSET(FILE_NAME_INFORMATION, FileName))
2094 {
2095 LocalReturnLength = FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2096 }
2097 }
2098
2099 /* If the provided buffer is too small, return the required size */
2100 if (LengthMismatch)
2101 {
2102 /* Add the required length */
2103 *ReturnLength += LocalFileInfo->FileNameLength;
2104
2105 /* Free the allocated buffer and return failure */
2106 Status = STATUS_BUFFER_OVERFLOW;
2107 _SEH2_LEAVE;
2108 }
2109
2110 /* Now calculate the new lengths left */
2111 FileLength = LocalReturnLength -
2112 FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
2113 LocalReturnLength = (ULONG)((ULONG_PTR)p -
2114 (ULONG_PTR)ObjectNameInfo +
2115 LocalFileInfo->FileNameLength);
2116
2117 /* Don't copy the name if it's not valid */
2118 if (LocalFileInfo->FileName[0] != OBJ_NAME_PATH_SEPARATOR)
2119 {
2120 /* Free the allocated buffer and return failure */
2121 Status = STATUS_OBJECT_PATH_INVALID;
2122 _SEH2_LEAVE;
2123 }
2124
2125 /* Write the Name and null-terminate it */
2126 RtlCopyMemory(p, LocalFileInfo->FileName, FileLength);
2127 p += (FileLength / sizeof(WCHAR));
2128 *p = UNICODE_NULL;
2129 LocalReturnLength += sizeof(UNICODE_NULL);
2130
2131 /* Return the length needed */
2132 *ReturnLength = LocalReturnLength;
2133
2134 /* Setup the length and maximum length */
2135 FileLength = (ULONG)((ULONG_PTR)p - (ULONG_PTR)ObjectNameInfo);
2136 ObjectNameInfo->Name.Length = (USHORT)FileLength -
2137 sizeof(OBJECT_NAME_INFORMATION);
2138 ObjectNameInfo->Name.MaximumLength = (USHORT)ObjectNameInfo->Name.Length +
2139 sizeof(UNICODE_NULL);
2140 }
2141 _SEH2_FINALLY
2142 {
2143 /* Free buffer and return */
2144 ExFreePoolWithTag(LocalInfo, TAG_IO);
2145 } _SEH2_END;
2146
2147 return Status;
2148 }
2149
2150 VOID
2151 NTAPI
2152 IopCloseFile(IN PEPROCESS Process OPTIONAL,
2153 IN PVOID ObjectBody,
2154 IN ACCESS_MASK GrantedAccess,
2155 IN ULONG HandleCount,
2156 IN ULONG SystemHandleCount)
2157 {
2158 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
2159 KEVENT Event;
2160 PIRP Irp;
2161 PIO_STACK_LOCATION StackPtr;
2162 NTSTATUS Status;
2163 PDEVICE_OBJECT DeviceObject;
2164 KIRQL OldIrql;
2165 IO_STATUS_BLOCK IoStatusBlock;
2166 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
2167
2168 /* If this isn't the last handle for the current process, quit */
2169 if (HandleCount != 1) return;
2170
2171 /* Check if the file is locked and has more then one handle opened */
2172 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
2173 {
2174 /* Check if this is a direct open or not */
2175 if (BooleanFlagOn(FileObject->Flags, FO_DIRECT_DEVICE_OPEN))
2176 {
2177 /* Get the attached device */
2178 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2179 }
2180 else
2181 {
2182 /* Get the FO's device */
2183 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2184 }
2185
2186 /* Check if this is a sync FO and lock it */
2187 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2188 {
2189 (VOID)IopLockFileObject(FileObject, KernelMode);
2190 }
2191
2192 /* Go the FastIO path if possible, otherwise fall back to IRP */
2193 if (DeviceObject->DriverObject->FastIoDispatch == NULL ||
2194 DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll == NULL ||
2195 !DeviceObject->DriverObject->FastIoDispatch->FastIoUnlockAll(FileObject, PsGetCurrentProcess(), &IoStatusBlock, DeviceObject))
2196 {
2197 /* Clear and set up Events */
2198 KeClearEvent(&FileObject->Event);
2199 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2200
2201 /* Allocate an IRP */
2202 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2203
2204 /* Set it up */
2205 Irp->UserEvent = &Event;
2206 Irp->UserIosb = &Irp->IoStatus;
2207 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2208 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2209 Irp->RequestorMode = KernelMode;
2210 Irp->Flags = IRP_SYNCHRONOUS_API;
2211 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2212 ObReferenceObject(FileObject);
2213
2214 /* Set up Stack Pointer Data */
2215 StackPtr = IoGetNextIrpStackLocation(Irp);
2216 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2217 StackPtr->MinorFunction = IRP_MN_UNLOCK_ALL;
2218 StackPtr->FileObject = FileObject;
2219
2220 /* Queue the IRP */
2221 IopQueueIrpToThread(Irp);
2222
2223 /* Call the FS Driver */
2224 Status = IoCallDriver(DeviceObject, Irp);
2225 if (Status == STATUS_PENDING)
2226 {
2227 /* Wait for completion */
2228 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2229 }
2230
2231 /* IO will unqueue & free for us */
2232 }
2233
2234 /* Release the lock if we were holding it */
2235 if (BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2236 {
2237 IopUnlockFileObject(FileObject);
2238 }
2239 }
2240
2241 /* Make sure this is the last handle */
2242 if (SystemHandleCount != 1) return;
2243
2244 /* Check if this is a direct open or not */
2245 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2246 {
2247 /* Get the attached device */
2248 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2249 }
2250 else
2251 {
2252 /* Get the FO's device */
2253 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2254 }
2255
2256 /* Set the handle created flag */
2257 FileObject->Flags |= FO_HANDLE_CREATED;
2258
2259 /* Check if this is a sync FO and lock it */
2260 if (Process != NULL &&
2261 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2262 {
2263 (VOID)IopLockFileObject(FileObject, KernelMode);
2264 }
2265
2266 /* Clear and set up Events */
2267 KeClearEvent(&FileObject->Event);
2268 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2269
2270 /* Allocate an IRP */
2271 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2272
2273 /* Set it up */
2274 Irp->UserEvent = &Event;
2275 Irp->UserIosb = &Irp->IoStatus;
2276 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2277 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2278 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2279 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2280
2281 /* Set up Stack Pointer Data */
2282 StackPtr = IoGetNextIrpStackLocation(Irp);
2283 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
2284 StackPtr->FileObject = FileObject;
2285
2286 /* Queue the IRP */
2287 IopQueueIrpToThread(Irp);
2288
2289 /* Update operation counts */
2290 IopUpdateOperationCount(IopOtherTransfer);
2291
2292 /* Call the FS Driver */
2293 Status = IoCallDriver(DeviceObject, Irp);
2294 if (Status == STATUS_PENDING)
2295 {
2296 /* Wait for completion */
2297 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2298 }
2299
2300 /* Unqueue the IRP */
2301 KeRaiseIrql(APC_LEVEL, &OldIrql);
2302 IopUnQueueIrpFromThread(Irp);
2303 KeLowerIrql(OldIrql);
2304
2305 /* Free the IRP */
2306 IoFreeIrp(Irp);
2307
2308 /* Release the lock if we were holding it */
2309 if (Process != NULL &&
2310 BooleanFlagOn(FileObject->Flags, FO_SYNCHRONOUS_IO))
2311 {
2312 IopUnlockFileObject(FileObject);
2313 }
2314 }
2315
2316 NTSTATUS
2317 NTAPI
2318 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2319 IN FILE_INFORMATION_CLASS FileInformationClass,
2320 IN ULONG FileInformationSize,
2321 OUT PVOID FileInformation)
2322 {
2323 NTSTATUS Status;
2324 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
2325 DUMMY_FILE_OBJECT LocalFileObject;
2326 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
2327 HANDLE Handle;
2328 OPEN_PACKET OpenPacket;
2329 BOOLEAN IsBasic;
2330 PAGED_CODE();
2331 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
2332
2333 /* Check if the caller was user mode */
2334 if (AccessMode != KernelMode)
2335 {
2336 /* Protect probe in SEH */
2337 _SEH2_TRY
2338 {
2339 /* Probe the buffer */
2340 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
2341 }
2342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2343 {
2344 /* Return the exception code */
2345 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2346 }
2347 _SEH2_END;
2348 }
2349
2350 /* Check if this is a basic or full request */
2351 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
2352
2353 /* Setup the Open Packet */
2354 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2355 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2356 OpenPacket.Size = sizeof(OPEN_PACKET);
2357 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
2358 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2359 OpenPacket.Disposition = FILE_OPEN;
2360 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
2361 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
2362 (AccessMode != KernelMode) ?
2363 &NetworkOpenInfo : FileInformation;
2364 OpenPacket.QueryOnly = TRUE;
2365 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
2366 OpenPacket.LocalFileObject = &LocalFileObject;
2367
2368 /* Update the operation count */
2369 IopUpdateOperationCount(IopOtherTransfer);
2370
2371 /*
2372 * Attempt opening the file. This will call the I/O Parse Routine for
2373 * the File Object (IopParseDevice) which will use the dummy file obejct
2374 * send the IRP to its device object. Note that we have two statuses
2375 * to worry about: the Object Manager's status (in Status) and the I/O
2376 * status, which is in the Open Packet's Final Status, and determined
2377 * by the Parse Check member.
2378 */
2379 Status = ObOpenObjectByName(ObjectAttributes,
2380 NULL,
2381 AccessMode,
2382 NULL,
2383 FILE_READ_ATTRIBUTES,
2384 &OpenPacket,
2385 &Handle);
2386 if (OpenPacket.ParseCheck == FALSE)
2387 {
2388 /* Parse failed */
2389 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2390 ObjectAttributes->ObjectName, Status);
2391 return Status;
2392 }
2393 else
2394 {
2395 /* Use the Io status */
2396 Status = OpenPacket.FinalStatus;
2397 }
2398
2399 /* Check if we were succesful and this was user mode and a full query */
2400 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
2401 {
2402 /* Enter SEH for copy */
2403 _SEH2_TRY
2404 {
2405 /* Copy the buffer back */
2406 RtlCopyMemory(FileInformation,
2407 &NetworkOpenInfo,
2408 FileInformationSize);
2409 }
2410 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2411 {
2412 /* Get exception code */
2413 Status = _SEH2_GetExceptionCode();
2414 }
2415 _SEH2_END;
2416 }
2417
2418 /* Return status */
2419 return Status;
2420 }
2421
2422 NTSTATUS
2423 NTAPI
2424 IopAcquireFileObjectLock(
2425 _In_ PFILE_OBJECT FileObject,
2426 _In_ KPROCESSOR_MODE WaitMode,
2427 _In_ BOOLEAN Alertable,
2428 _Out_ PBOOLEAN LockFailed)
2429 {
2430 NTSTATUS Status;
2431
2432 PAGED_CODE();
2433
2434 InterlockedIncrement((PLONG)&FileObject->Waiters);
2435
2436 Status = STATUS_SUCCESS;
2437 do
2438 {
2439 if (!InterlockedExchange((PLONG)&FileObject->Busy, TRUE))
2440 {
2441 break;
2442 }
2443 Status = KeWaitForSingleObject(&FileObject->Lock,
2444 Executive,
2445 WaitMode,
2446 Alertable,
2447 NULL);
2448 } while (Status == STATUS_SUCCESS);
2449
2450 InterlockedDecrement((PLONG)&FileObject->Waiters);
2451 if (Status == STATUS_SUCCESS)
2452 {
2453 ObReferenceObject(FileObject);
2454 *LockFailed = FALSE;
2455 }
2456 else
2457 {
2458 if (!FileObject->Busy && FileObject->Waiters)
2459 {
2460 KeSetEvent(&FileObject->Lock, IO_NO_INCREMENT, FALSE);
2461 }
2462 *LockFailed = TRUE;
2463 }
2464
2465 return Status;
2466 }
2467
2468 PVOID
2469 NTAPI
2470 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
2471 {
2472 if (BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2473 {
2474 PFILE_OBJECT_EXTENSION FileObjectExtension;
2475
2476 FileObjectExtension = FileObject->FileObjectExtension;
2477 return FileObjectExtension->FilterContext;
2478 }
2479
2480 return NULL;
2481 }
2482
2483 NTSTATUS
2484 NTAPI
2485 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
2486 IN PVOID FilterContext,
2487 IN BOOLEAN Define)
2488 {
2489 ULONG_PTR Success;
2490 PFILE_OBJECT_EXTENSION FileObjectExtension;
2491
2492 if (!BooleanFlagOn(FileObject->Flags, FO_FILE_OBJECT_HAS_EXTENSION))
2493 {
2494 return STATUS_INVALID_PARAMETER;
2495 }
2496
2497 FileObjectExtension = FileObject->FileObjectExtension;
2498 if (Define)
2499 {
2500 /* If define, just set the new value if not value is set
2501 * Success will only contain old value. It is valid if it is NULL
2502 */
2503 Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, FilterContext, NULL);
2504 }
2505 else
2506 {
2507 /* If not define, we want to reset filter context.
2508 * We will remove value (provided by the caller) and set NULL instead.
2509 * This will only success if caller provides correct previous value.
2510 * To catch whether it worked, we substract previous value to expect value:
2511 * If it matches (and thus, we reset), Success will contain 0
2512 * Otherwise, it will contain a non-zero value.
2513 */
2514 Success = (ULONG_PTR)InterlockedCompareExchangePointer(&FileObjectExtension->FilterContext, NULL, FilterContext) - (ULONG_PTR)FilterContext;
2515 }
2516
2517 /* If success isn't 0, it means we failed somewhere (set or unset) */
2518 if (Success != 0)
2519 {
2520 return STATUS_ALREADY_COMMITTED;
2521 }
2522
2523 return STATUS_SUCCESS;
2524 }
2525
2526 NTSTATUS
2527 NTAPI
2528 IopCreateFile(OUT PHANDLE FileHandle,
2529 IN ACCESS_MASK DesiredAccess,
2530 IN POBJECT_ATTRIBUTES ObjectAttributes,
2531 OUT PIO_STATUS_BLOCK IoStatusBlock,
2532 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2533 IN ULONG FileAttributes,
2534 IN ULONG ShareAccess,
2535 IN ULONG Disposition,
2536 IN ULONG CreateOptions,
2537 IN PVOID EaBuffer OPTIONAL,
2538 IN ULONG EaLength,
2539 IN CREATE_FILE_TYPE CreateFileType,
2540 IN PVOID ExtraCreateParameters OPTIONAL,
2541 IN ULONG Options,
2542 IN ULONG Flags,
2543 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2544 {
2545 KPROCESSOR_MODE AccessMode;
2546 HANDLE LocalHandle = 0;
2547 LARGE_INTEGER SafeAllocationSize;
2548 NTSTATUS Status = STATUS_SUCCESS;
2549 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
2550 POPEN_PACKET OpenPacket;
2551 ULONG EaErrorOffset;
2552 PAGED_CODE();
2553
2554 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2555
2556
2557 /* Check if we have no parameter checking to do */
2558 if (Options & IO_NO_PARAMETER_CHECKING)
2559 {
2560 /* Then force kernel-mode access to avoid checks */
2561 AccessMode = KernelMode;
2562 }
2563 else
2564 {
2565 /* Otherwise, use the actual mode */
2566 AccessMode = ExGetPreviousMode();
2567 }
2568
2569 /* Check if we need to do parameter checking */
2570 if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
2571 {
2572 /* Validate parameters */
2573 if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
2574 {
2575 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2576 return STATUS_INVALID_PARAMETER;
2577 }
2578
2579 if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
2580 {
2581 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2582 return STATUS_INVALID_PARAMETER;
2583 }
2584
2585 if (Disposition > FILE_MAXIMUM_DISPOSITION)
2586 {
2587 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2588 return STATUS_INVALID_PARAMETER;
2589 }
2590
2591 if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
2592 {
2593 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2594 return STATUS_INVALID_PARAMETER;
2595 }
2596
2597 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
2598 (!(DesiredAccess & SYNCHRONIZE)))
2599 {
2600 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2601 return STATUS_INVALID_PARAMETER;
2602 }
2603
2604 if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
2605 {
2606 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2607 return STATUS_INVALID_PARAMETER;
2608 }
2609
2610 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
2611 (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
2612 {
2613 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2614 return STATUS_INVALID_PARAMETER;
2615 }
2616
2617 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2618 (CreateOptions & ~(FILE_DIRECTORY_FILE |
2619 FILE_SYNCHRONOUS_IO_ALERT |
2620 FILE_SYNCHRONOUS_IO_NONALERT |
2621 FILE_WRITE_THROUGH |
2622 FILE_COMPLETE_IF_OPLOCKED |
2623 FILE_OPEN_FOR_BACKUP_INTENT |
2624 FILE_DELETE_ON_CLOSE |
2625 FILE_OPEN_FOR_FREE_SPACE_QUERY |
2626 FILE_OPEN_BY_FILE_ID |
2627 FILE_NO_COMPRESSION |
2628 FILE_OPEN_REPARSE_POINT)))
2629 {
2630 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2631 return STATUS_INVALID_PARAMETER;
2632 }
2633
2634 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2635 (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
2636 {
2637 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2638 return STATUS_INVALID_PARAMETER;
2639 }
2640
2641 if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
2642 {
2643 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2644 return STATUS_INVALID_PARAMETER;
2645 }
2646
2647 if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
2648 {
2649 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2650 return STATUS_INVALID_PARAMETER;
2651 }
2652
2653 /* Now check if this is a named pipe */
2654 if (CreateFileType == CreateFileTypeNamedPipe)
2655 {
2656 /* Make sure we have extra parameters */
2657 if (!ExtraCreateParameters)
2658 {
2659 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2660 return STATUS_INVALID_PARAMETER;
2661 }
2662
2663 /* Get the parameters and validate them */
2664 NamedPipeCreateParameters = ExtraCreateParameters;
2665 if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
2666 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
2667 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
2668 (ShareAccess & FILE_SHARE_DELETE) ||
2669 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
2670 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
2671 {
2672 /* Invalid named pipe create */
2673 DPRINT1("Invalid named pipe create\n");
2674 return STATUS_INVALID_PARAMETER;
2675 }
2676 }
2677 else if (CreateFileType == CreateFileTypeMailslot)
2678 {
2679 /* Make sure we have extra parameters */
2680 if (!ExtraCreateParameters)
2681 {
2682 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2683 return STATUS_INVALID_PARAMETER;
2684 }
2685
2686 /* Get the parameters and validate them */
2687 if ((ShareAccess & FILE_SHARE_DELETE) ||
2688 !(ShareAccess & ~FILE_SHARE_WRITE) ||
2689 (Disposition != FILE_CREATE) ||
2690 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
2691 {
2692 /* Invalid mailslot create */
2693 DPRINT1("Invalid mailslot create\n");
2694 return STATUS_INVALID_PARAMETER;
2695 }
2696 }
2697 }
2698
2699 /* Allocate the open packet */
2700 OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
2701 if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
2702 RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
2703
2704 /* Check if the call came from user mode */
2705 if (AccessMode != KernelMode)
2706 {
2707 _SEH2_TRY
2708 {
2709 /* Probe the output parameters */
2710 ProbeForWriteHandle(FileHandle);
2711 ProbeForWriteIoStatusBlock(IoStatusBlock);
2712
2713 /* Probe the allocation size if one was passed in */
2714 if (AllocationSize)
2715 {
2716 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
2717 }
2718 else
2719 {
2720 SafeAllocationSize.QuadPart = 0;
2721 }
2722
2723 /* Make sure it's valid */
2724 if (SafeAllocationSize.QuadPart < 0)
2725 {
2726 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
2727 }
2728
2729 /* Check if EA was passed in */
2730 if ((EaBuffer) && (EaLength))
2731 {
2732 /* Probe it */
2733 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
2734
2735 /* And marshall it */
2736 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2737 EaLength,
2738 TAG_EA);
2739 OpenPacket->EaLength = EaLength;
2740 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2741
2742 /* Validate the buffer */
2743 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2744 EaLength,
2745 &EaErrorOffset);
2746 if (!NT_SUCCESS(Status))
2747 {
2748 /* Undo everything if it's invalid */
2749 DPRINT1("Invalid EA buffer\n");
2750 IoStatusBlock->Status = Status;
2751 IoStatusBlock->Information = EaErrorOffset;
2752 RtlRaiseStatus(Status);
2753 }
2754 }
2755 }
2756 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2757 {
2758 /* Return the exception code */
2759 if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
2760 ExFreePool(OpenPacket);
2761 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2762 }
2763 _SEH2_END;
2764 }
2765 else
2766 {
2767 /* Check if this is a device attach */
2768 if (CreateOptions & IO_ATTACH_DEVICE_API)
2769 {
2770 /* Set the flag properly */
2771 Options |= IO_ATTACH_DEVICE;
2772 CreateOptions &= ~IO_ATTACH_DEVICE_API;
2773 }
2774
2775 /* Check if we have allocation size */
2776 if (AllocationSize)
2777 {
2778 /* Capture it */
2779 SafeAllocationSize = *AllocationSize;
2780 }
2781 else
2782 {
2783 /* Otherwise, no size */
2784 SafeAllocationSize.QuadPart = 0;
2785 }
2786
2787 /* Check if we have an EA packet */
2788 if ((EaBuffer) && (EaLength))
2789 {
2790 /* Allocate the kernel copy */
2791 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2792 EaLength,
2793 TAG_EA);
2794 if (!OpenPacket->EaBuffer)
2795 {
2796 ExFreePool(OpenPacket);
2797 DPRINT1("Failed to allocate open packet EA buffer\n");
2798 return STATUS_INSUFFICIENT_RESOURCES;
2799 }
2800
2801 /* Copy the data */
2802 OpenPacket->EaLength = EaLength;
2803 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2804
2805 /* Validate the buffer */
2806 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2807 EaLength,
2808 &EaErrorOffset);
2809 if (!NT_SUCCESS(Status))
2810 {
2811 /* Undo everything if it's invalid */
2812 DPRINT1("Invalid EA buffer\n");
2813 ExFreePool(OpenPacket->EaBuffer);
2814 IoStatusBlock->Status = Status;
2815 IoStatusBlock->Information = EaErrorOffset;
2816 ExFreePool(OpenPacket);
2817 return Status;
2818 }
2819 }
2820 }
2821
2822 /* Setup the Open Packet */
2823 OpenPacket->Type = IO_TYPE_OPEN_PACKET;
2824 OpenPacket->Size = sizeof(*OpenPacket);
2825 OpenPacket->AllocationSize = SafeAllocationSize;
2826 OpenPacket->CreateOptions = CreateOptions;
2827 OpenPacket->FileAttributes = (USHORT)FileAttributes;
2828 OpenPacket->ShareAccess = (USHORT)ShareAccess;
2829 OpenPacket->Options = Options;
2830 OpenPacket->Disposition = Disposition;
2831 OpenPacket->CreateFileType = CreateFileType;
2832 OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
2833 OpenPacket->InternalFlags = Flags;
2834 OpenPacket->TopDeviceObjectHint = DeviceObject;
2835
2836 /* Update the operation count */
2837 IopUpdateOperationCount(IopOtherTransfer);
2838
2839 /*
2840 * Attempt opening the file. This will call the I/O Parse Routine for
2841 * the File Object (IopParseDevice) which will create the object and
2842 * send the IRP to its device object. Note that we have two statuses
2843 * to worry about: the Object Manager's status (in Status) and the I/O
2844 * status, which is in the Open Packet's Final Status, and determined
2845 * by the Parse Check member.
2846 */
2847 Status = ObOpenObjectByName(ObjectAttributes,
2848 NULL,
2849 AccessMode,
2850 NULL,
2851 DesiredAccess,
2852 OpenPacket,
2853 &LocalHandle);
2854
2855 /* Free the EA Buffer */
2856 if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2857
2858 /* Now check for Ob or Io failure */
2859 if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
2860 {
2861 /* Check if Ob thinks well went well */
2862 if (NT_SUCCESS(Status))
2863 {
2864 /*
2865 * Tell it otherwise. Because we didn't use an ObjectType,
2866 * it incorrectly returned us a handle to God knows what.
2867 */
2868 ZwClose(LocalHandle);
2869 Status = STATUS_OBJECT_TYPE_MISMATCH;
2870 }
2871
2872 /* Now check the Io status */
2873 if (!NT_SUCCESS(OpenPacket->FinalStatus))
2874 {
2875 /* Use this status instead of Ob's */
2876 Status = OpenPacket->FinalStatus;
2877
2878 /* Check if it was only a warning */
2879 if (NT_WARNING(Status))
2880 {
2881 /* Protect write with SEH */
2882 _SEH2_TRY
2883 {
2884 /* In this case, we copy the I/O Status back */
2885 IoStatusBlock->Information = OpenPacket->Information;
2886 IoStatusBlock->Status = OpenPacket->FinalStatus;
2887 }
2888 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2889 {
2890 /* Get exception code */
2891 Status = _SEH2_GetExceptionCode();
2892 }
2893 _SEH2_END;
2894 }
2895 }
2896 else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
2897 {
2898 /*
2899 * This can happen in the very bizarre case where the parse routine
2900 * actually executed more then once (due to a reparse) and ended
2901 * up failing after already having created the File Object.
2902 */
2903 if (OpenPacket->FileObject->FileName.Length)
2904 {
2905 /* It had a name, free it */
2906 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2907 }
2908
2909 /* Clear the device object to invalidate the FO, and dereference */
2910 OpenPacket->FileObject->DeviceObject = NULL;
2911 ObDereferenceObject(OpenPacket->FileObject);
2912 }
2913 }
2914 else
2915 {
2916 /* We reached success and have a valid file handle */
2917 OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2918 ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2919
2920 /* Enter SEH for write back */
2921 _SEH2_TRY
2922 {
2923 /* Write back the handle and I/O Status */
2924 *FileHandle = LocalHandle;
2925 IoStatusBlock->Information = OpenPacket->Information;
2926 IoStatusBlock->Status = OpenPacket->FinalStatus;
2927
2928 /* Get the Io status */
2929 Status = OpenPacket->FinalStatus;
2930 }
2931 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2932 {
2933 /* Get the exception status */
2934 Status = _SEH2_GetExceptionCode();
2935 }
2936 _SEH2_END;
2937 }
2938
2939 /* Check if we were 100% successful */
2940 if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
2941 {
2942 /* Dereference the File Object */
2943 ObDereferenceObject(OpenPacket->FileObject);
2944 }
2945
2946 /* Return status */
2947 ExFreePool(OpenPacket);
2948 return Status;
2949 }
2950
2951 /* FUNCTIONS *****************************************************************/
2952
2953 /*
2954 * @unimplemented
2955 */
2956 NTSTATUS
2957 NTAPI
2958 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
2959 IN ULONG Length,
2960 IN BOOLEAN SetOperation)
2961 {
2962 UNIMPLEMENTED;
2963 return STATUS_NOT_IMPLEMENTED;
2964 }
2965
2966 /*
2967 * @unimplemented
2968 */
2969 NTSTATUS
2970 NTAPI
2971 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
2972 IN ULONG QuotaLength,
2973 OUT PULONG ErrorOffset)
2974 {
2975 UNIMPLEMENTED;
2976 return STATUS_NOT_IMPLEMENTED;
2977 }
2978
2979 /*
2980 * @implemented
2981 */
2982 NTSTATUS
2983 NTAPI
2984 IoCreateFile(OUT PHANDLE FileHandle,
2985 IN ACCESS_MASK DesiredAccess,
2986 IN POBJECT_ATTRIBUTES ObjectAttributes,
2987 OUT PIO_STATUS_BLOCK IoStatusBlock,
2988 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2989 IN ULONG FileAttributes,
2990 IN ULONG ShareAccess,
2991 IN ULONG Disposition,
2992 IN ULONG CreateOptions,
2993 IN PVOID EaBuffer OPTIONAL,
2994 IN ULONG EaLength,
2995 IN CREATE_FILE_TYPE CreateFileType,
2996 IN PVOID ExtraCreateParameters OPTIONAL,
2997 IN ULONG Options)
2998 {
2999 PAGED_CODE();
3000
3001 return IopCreateFile(FileHandle,
3002 DesiredAccess,
3003 ObjectAttributes,
3004 IoStatusBlock,
3005 AllocationSize,
3006 FileAttributes,
3007 ShareAccess,
3008 Disposition,
3009 CreateOptions,
3010 EaBuffer,
3011 EaLength,
3012 CreateFileType,
3013 ExtraCreateParameters,
3014 Options,
3015 0,
3016 NULL);
3017 }
3018
3019 /*
3020 * @unimplemented
3021 */
3022 NTSTATUS
3023 NTAPI
3024 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
3025 IN ACCESS_MASK DesiredAccess,
3026 IN POBJECT_ATTRIBUTES ObjectAttributes,
3027 OUT PIO_STATUS_BLOCK IoStatusBlock,
3028 IN PLARGE_INTEGER AllocationSize OPTIONAL,
3029 IN ULONG FileAttributes,
3030 IN ULONG ShareAccess,
3031 IN ULONG Disposition,
3032 IN ULONG CreateOptions,
3033 IN PVOID EaBuffer OPTIONAL,
3034 IN ULONG EaLength,
3035 IN CREATE_FILE_TYPE CreateFileType,
3036 IN PVOID ExtraCreateParameters OPTIONAL,
3037 IN ULONG Options,
3038 IN PVOID DeviceObject)
3039 {
3040 ULONG Flags = 0;
3041
3042 PAGED_CODE();
3043
3044 /* Check if we were passed a device to send the create request to*/
3045 if (DeviceObject)
3046 {
3047 /* We'll tag this request into a file object extension */
3048 Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
3049 }
3050
3051 return IopCreateFile(FileHandle,
3052 DesiredAccess,
3053 ObjectAttributes,
3054 IoStatusBlock,
3055 AllocationSize,
3056 FileAttributes,
3057 ShareAccess,
3058 Disposition,
3059 CreateOptions,
3060 EaBuffer,
3061 EaLength,
3062 CreateFileType,
3063 ExtraCreateParameters,
3064 Options | IO_NO_PARAMETER_CHECKING,
3065 Flags,
3066 DeviceObject);
3067 }
3068
3069 /*
3070 * @implemented
3071 */
3072 PFILE_OBJECT
3073 NTAPI
3074 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
3075 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
3076 OUT PHANDLE FileObjectHandle OPTIONAL)
3077 {
3078 PFILE_OBJECT CreatedFileObject;
3079 NTSTATUS Status;
3080 HANDLE FileHandle;
3081 OBJECT_ATTRIBUTES ObjectAttributes;
3082 PAGED_CODE();
3083 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3084
3085 /* Choose Device Object */
3086 if (FileObject) DeviceObject = FileObject->DeviceObject;
3087
3088 /* Reference the device object and initialize attributes */
3089 InterlockedIncrement(&DeviceObject->ReferenceCount);
3090 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3091
3092 /* Create the File Object */
3093 Status = ObCreateObject(KernelMode,
3094 IoFileObjectType,
3095 &ObjectAttributes,
3096 KernelMode,
3097 NULL,
3098 sizeof(FILE_OBJECT),
3099 sizeof(FILE_OBJECT),
3100 0,
3101 (PVOID*)&CreatedFileObject);
3102 if (!NT_SUCCESS(Status))
3103 {
3104 /* Fail */
3105 IopDereferenceDeviceObject(DeviceObject, FALSE);
3106 ExRaiseStatus(Status);
3107 }
3108
3109 /* Set File Object Data */
3110 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3111 CreatedFileObject->DeviceObject = DeviceObject;
3112 CreatedFileObject->Type = IO_TYPE_FILE;
3113 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3114 CreatedFileObject->Flags = FO_STREAM_FILE;
3115
3116 /* Initialize the wait event */
3117 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3118
3119 /* Insert it to create a handle for it */
3120 Status = ObInsertObject(CreatedFileObject,
3121 NULL,
3122 FILE_READ_DATA,
3123 1,
3124 (PVOID*)&CreatedFileObject,
3125 &FileHandle);
3126 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
3127
3128 /* Set the handle created flag */
3129 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3130 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3131
3132 /* Check if we have a VPB */
3133 if (DeviceObject->Vpb)
3134 {
3135 /* Reference it */
3136 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3137 }
3138
3139 /* Check if the caller wants the handle */
3140 if (FileObjectHandle)
3141 {
3142 /* Return it */
3143 *FileObjectHandle = FileHandle;
3144 ObDereferenceObject(CreatedFileObject);
3145 }
3146 else
3147 {
3148 /* Otherwise, close it */
3149 ObCloseHandle(FileHandle, KernelMode);
3150 }
3151
3152 /* Return the file object */
3153 return CreatedFileObject;
3154 }
3155
3156 /*
3157 * @implemented
3158 */
3159 PFILE_OBJECT
3160 NTAPI
3161 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
3162 IN PDEVICE_OBJECT DeviceObject)
3163 {
3164 /* Call the newer function */
3165 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
3166 }
3167
3168 /*
3169 * @implemented
3170 */
3171 PFILE_OBJECT
3172 NTAPI
3173 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
3174 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
3175 {
3176 PFILE_OBJECT CreatedFileObject;
3177 NTSTATUS Status;
3178 OBJECT_ATTRIBUTES ObjectAttributes;
3179 PAGED_CODE();
3180 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
3181
3182 /* Choose Device Object */
3183 if (FileObject) DeviceObject = FileObject->DeviceObject;
3184
3185 /* Reference the device object and initialize attributes */
3186 InterlockedIncrement(&DeviceObject->ReferenceCount);
3187 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
3188
3189 /* Create the File Object */
3190 Status = ObCreateObject(KernelMode,
3191 IoFileObjectType,
3192 &ObjectAttributes,
3193 KernelMode,
3194 NULL,
3195 sizeof(FILE_OBJECT),
3196 sizeof(FILE_OBJECT),
3197 0,
3198 (PVOID*)&CreatedFileObject);
3199 if (!NT_SUCCESS(Status))
3200 {
3201 /* Fail */
3202 IopDereferenceDeviceObject(DeviceObject, FALSE);
3203 ExRaiseStatus(Status);
3204 }
3205
3206 /* Set File Object Data */
3207 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
3208 CreatedFileObject->DeviceObject = DeviceObject;
3209 CreatedFileObject->Type = IO_TYPE_FILE;
3210 CreatedFileObject->Size = sizeof(FILE_OBJECT);
3211 CreatedFileObject->Flags = FO_STREAM_FILE;
3212
3213 /* Initialize the wait event */
3214 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
3215
3216 /* Destroy create information */
3217 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
3218 ObjectCreateInfo);
3219 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
3220
3221 /* Set the handle created flag */
3222 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
3223 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
3224
3225 /* Check if we have a VPB */
3226 if (DeviceObject->Vpb)
3227 {
3228 /* Reference it */
3229 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
3230 }
3231
3232 /* Return the file object */
3233 return CreatedFileObject;
3234 }
3235
3236 /*
3237 * @implemented
3238 */
3239 PGENERIC_MAPPING
3240 NTAPI
3241 IoGetFileObjectGenericMapping(VOID)
3242 {
3243 /* Return the mapping */
3244 return &IopFileMapping;
3245 }
3246
3247 /*
3248 * @implemented
3249 */
3250 BOOLEAN
3251 NTAPI
3252 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
3253 {
3254 /* Return the flag status */
3255 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3256 }
3257
3258 /*
3259 * @implemented
3260 */
3261 BOOLEAN
3262 NTAPI
3263 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
3264 IN ACCESS_MASK DesiredAccess,
3265 IN ULONG OpenOptions,
3266 OUT PIO_STATUS_BLOCK IoStatus,
3267 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
3268 {
3269 NTSTATUS Status;
3270 DUMMY_FILE_OBJECT LocalFileObject;
3271 HANDLE Handle;
3272 OPEN_PACKET OpenPacket;
3273 PAGED_CODE();
3274 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
3275
3276 /* Setup the Open Packet */
3277 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3278 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3279 OpenPacket.Size = sizeof(OPEN_PACKET);
3280 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
3281 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
3282 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
3283 OpenPacket.Disposition = FILE_OPEN;
3284 OpenPacket.NetworkInformation = Buffer;
3285 OpenPacket.QueryOnly = TRUE;
3286 OpenPacket.FullAttributes = TRUE;
3287 OpenPacket.LocalFileObject = &LocalFileObject;
3288
3289 /*
3290 * Attempt opening the file. This will call the I/O Parse Routine for
3291 * the File Object (IopParseDevice) which will use the dummy file obejct
3292 * send the IRP to its device object. Note that we have two statuses
3293 * to worry about: the Object Manager's status (in Status) and the I/O
3294 * status, which is in the Open Packet's Final Status, and determined
3295 * by the Parse Check member.
3296 */
3297 Status = ObOpenObjectByName(ObjectAttributes,
3298 NULL,
3299 KernelMode,
3300 NULL,
3301 DesiredAccess,
3302 &OpenPacket,
3303 &Handle);
3304 if (OpenPacket.ParseCheck == FALSE)
3305 {
3306 /* Parse failed */
3307 IoStatus->Status = Status;
3308 }
3309 else
3310 {
3311 /* Use the Io status */
3312 IoStatus->Status = OpenPacket.FinalStatus;
3313 IoStatus->Information = OpenPacket.Information;
3314 }
3315
3316 /* Return success */
3317 return TRUE;
3318 }
3319
3320 /*
3321 * @implemented
3322 */
3323 VOID
3324 NTAPI
3325 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
3326 OUT PSHARE_ACCESS ShareAccess)
3327 {
3328 PAGED_CODE();
3329
3330 /* Check if the file has an extension */
3331 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3332 {
3333 /* Check if caller specified to ignore access checks */
3334 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3335 {
3336 /* Don't update share access */
3337 return;
3338 }
3339 }
3340
3341 /* Otherwise, check if there's any access present */
3342 if ((FileObject->ReadAccess) ||
3343 (FileObject->WriteAccess) ||
3344 (FileObject->DeleteAccess))
3345 {
3346 /* Increase the open count */
3347 ShareAccess->OpenCount++;
3348
3349 /* Add new share access */
3350 ShareAccess->Readers += FileObject->ReadAccess;
3351 ShareAccess->Writers += FileObject->WriteAccess;
3352 ShareAccess->Deleters += FileObject->DeleteAccess;
3353 ShareAccess->SharedRead += FileObject->SharedRead;
3354 ShareAccess->SharedWrite += FileObject->SharedWrite;
3355 ShareAccess->SharedDelete += FileObject->SharedDelete;
3356 }
3357 }
3358
3359 /*
3360 * @implemented
3361 */
3362 NTSTATUS
3363 NTAPI
3364 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
3365 IN ULONG DesiredShareAccess,
3366 IN PFILE_OBJECT FileObject,
3367 IN PSHARE_ACCESS ShareAccess,
3368 IN BOOLEAN Update)
3369 {
3370 BOOLEAN ReadAccess;
3371 BOOLEAN WriteAccess;
3372 BOOLEAN DeleteAccess;
3373 BOOLEAN SharedRead;
3374 BOOLEAN SharedWrite;
3375 BOOLEAN SharedDelete;
3376 PAGED_CODE();
3377
3378 /* Get access masks */
3379 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3380 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3381 DeleteAccess = (DesiredAccess & DELETE) != 0;
3382
3383 /* Set them in the file object */
3384 FileObject->ReadAccess = ReadAccess;
3385 FileObject->WriteAccess = WriteAccess;
3386 FileObject->DeleteAccess = DeleteAccess;
3387
3388 /* Check if the file has an extension */
3389 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3390 {
3391 /* Check if caller specified to ignore access checks */
3392 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3393 {
3394 /* Don't check share access */
3395 return STATUS_SUCCESS;
3396 }
3397 }
3398
3399 /* Check if we have any access */
3400 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
3401 {
3402 /* Get shared access masks */
3403 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3404 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3405 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3406
3407 /* Set them */
3408 FileObject->SharedRead = SharedRead;
3409 FileObject->SharedWrite = SharedWrite;
3410 FileObject->SharedDelete = SharedDelete;
3411
3412 /* Check if the shared access is violated */
3413 if ((ReadAccess &&
3414 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
3415 (WriteAccess &&
3416 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
3417 (DeleteAccess &&
3418 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
3419 ((ShareAccess->Readers != 0) && !SharedRead) ||
3420 ((ShareAccess->Writers != 0) && !SharedWrite) ||
3421 ((ShareAccess->Deleters != 0) && !SharedDelete))
3422 {
3423 /* Sharing violation, fail */
3424 return STATUS_SHARING_VIOLATION;
3425 }
3426
3427 /* It's not, check if caller wants us to update it */
3428 if (Update)
3429 {
3430 /* Increase open count */
3431 ShareAccess->OpenCount++;
3432
3433 /* Update shared access */
3434 ShareAccess->Readers += ReadAccess;
3435 ShareAccess->Writers += WriteAccess;
3436 ShareAccess->Deleters += DeleteAccess;
3437 ShareAccess->SharedRead += SharedRead;
3438 ShareAccess->SharedWrite += SharedWrite;
3439 ShareAccess->SharedDelete += SharedDelete;
3440 }
3441 }
3442
3443 /* Validation successful */
3444 return STATUS_SUCCESS;
3445 }
3446
3447 /*
3448 * @implemented
3449 */
3450 VOID
3451 NTAPI
3452 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
3453 IN PSHARE_ACCESS ShareAccess)
3454 {
3455 PAGED_CODE();
3456
3457 /* Check if the file has an extension */
3458 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3459 {
3460 /* Check if caller specified to ignore access checks */
3461 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3462 {
3463 /* Don't update share access */
3464 return;
3465 }
3466 }
3467
3468 /* Otherwise, check if there's any access present */
3469 if ((FileObject->ReadAccess) ||
3470 (FileObject->WriteAccess) ||
3471 (FileObject->DeleteAccess))
3472 {
3473 /* Decrement the open count */
3474 ShareAccess->OpenCount--;
3475
3476 /* Remove share access */
3477 ShareAccess->Readers -= FileObject->ReadAccess;
3478 ShareAccess->Writers -= FileObject->WriteAccess;
3479 ShareAccess->Deleters -= FileObject->DeleteAccess;
3480 ShareAccess->SharedRead -= FileObject->SharedRead;
3481 ShareAccess->SharedWrite -= FileObject->SharedWrite;
3482 ShareAccess->SharedDelete -= FileObject->SharedDelete;
3483 }
3484 }
3485
3486 /*
3487 * @implemented
3488 */
3489 VOID
3490 NTAPI
3491 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
3492 IN ULONG DesiredShareAccess,
3493 IN PFILE_OBJECT FileObject,
3494 OUT PSHARE_ACCESS ShareAccess)
3495 {
3496 BOOLEAN ReadAccess;
3497 BOOLEAN WriteAccess;
3498 BOOLEAN DeleteAccess;
3499 BOOLEAN SharedRead;
3500 BOOLEAN SharedWrite;
3501 BOOLEAN SharedDelete;
3502 BOOLEAN Update = TRUE;
3503 PAGED_CODE();
3504
3505 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3506 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3507 DeleteAccess = (DesiredAccess & DELETE) != 0;
3508
3509 /* Check if the file has an extension */
3510 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3511 {
3512 /* Check if caller specified to ignore access checks */
3513 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3514 {
3515 /* Don't update share access */
3516 Update = FALSE;
3517 }
3518 }
3519
3520 /* Update basic access */
3521 FileObject->ReadAccess = ReadAccess;
3522 FileObject->WriteAccess = WriteAccess;
3523 FileObject->DeleteAccess = DeleteAccess;
3524
3525 /* Check if we have no access as all */
3526 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
3527 {
3528 /* Check if we need to update the structure */
3529 if (!Update) return;
3530
3531 /* Otherwise, clear data */
3532 ShareAccess->OpenCount = 0;
3533 ShareAccess->Readers = 0;
3534 ShareAccess->Writers = 0;
3535 ShareAccess->Deleters = 0;
3536 ShareAccess->SharedRead = 0;
3537 ShareAccess->SharedWrite = 0;
3538 ShareAccess->SharedDelete = 0;
3539 }
3540 else
3541 {
3542 /* Calculate shared access */
3543 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3544 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3545 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3546
3547 /* Set it in the FO */
3548 FileObject->SharedRead = SharedRead;
3549 FileObject->SharedWrite = SharedWrite;
3550 FileObject->SharedDelete = SharedDelete;
3551
3552 /* Check if we need to update the structure */
3553 if (!Update) return;
3554
3555 /* Otherwise, set data */
3556 ShareAccess->OpenCount = 1;
3557 ShareAccess->Readers = ReadAccess;
3558 ShareAccess->Writers = WriteAccess;
3559 ShareAccess->Deleters = DeleteAccess;
3560 ShareAccess->SharedRead = SharedRead;
3561 ShareAccess->SharedWrite = SharedWrite;
3562 ShareAccess->SharedDelete = SharedDelete;
3563 }
3564 }
3565
3566 /*
3567 * @implemented
3568 */
3569 VOID
3570 NTAPI
3571 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
3572 IN PFILE_OBJECT FileObject)
3573 {
3574 PIRP Irp;
3575 KEVENT Event;
3576 KIRQL OldIrql;
3577 NTSTATUS Status;
3578 PIO_STACK_LOCATION Stack;
3579
3580 /* Check if handles were already created for the
3581 * open file. If so, that's over.
3582 */
3583 if (FileObject->Flags & FO_HANDLE_CREATED)
3584 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
3585 (ULONG_PTR)FileObject,
3586 (ULONG_PTR)DeviceObject, 0, 0);
3587
3588 /* Reset the events */
3589 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
3590 KeClearEvent(&FileObject->Event);
3591
3592 /* Allocate the IRP we'll use */
3593 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
3594 /* Properly set it */
3595 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3596 Irp->UserEvent = &Event;
3597 Irp->UserIosb = &Irp->IoStatus;
3598 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3599 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3600 Irp->RequestorMode = KernelMode;
3601 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
3602
3603 Stack = IoGetNextIrpStackLocation(Irp);
3604 Stack->MajorFunction = IRP_MJ_CLEANUP;
3605 Stack->FileObject = FileObject;
3606
3607 /* Put on top of IRPs list of the thread */
3608 IopQueueIrpToThread(Irp);
3609
3610 /* Call the driver */
3611 Status = IoCallDriver(DeviceObject, Irp);
3612 if (Status == STATUS_PENDING)
3613 {
3614 KeWaitForSingleObject(&Event, UserRequest,
3615 KernelMode, FALSE, NULL);
3616 }
3617
3618 /* Remove from IRPs list */
3619 KeRaiseIrql(APC_LEVEL, &OldIrql);
3620 IopUnQueueIrpFromThread(Irp);
3621 KeLowerIrql(OldIrql);
3622
3623 /* Free the IRP */
3624 IoFreeIrp(Irp);
3625
3626 /* Clear the event */
3627 KeClearEvent(&FileObject->Event);
3628 /* And finally, mark the open operation as canceled */
3629 FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
3630 }
3631
3632 /*
3633 * @implemented
3634 */
3635 NTSTATUS
3636 NTAPI
3637 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
3638 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
3639 {
3640 NTSTATUS Status;
3641 ULONG Length, ReturnLength;
3642 POBJECT_NAME_INFORMATION LocalInfo;
3643
3644 /* Start with a buffer length of 200 */
3645 ReturnLength = 200;
3646 /*
3647 * We'll loop until query works.
3648 * We will use returned length for next loop
3649 * iteration, trying to have a big enough buffer.
3650 */
3651 for (Length = 200; ; Length = ReturnLength)
3652 {
3653 /* Allocate our work buffer */
3654 LocalInfo = ExAllocatePoolWithTag(PagedPool, Length, 'nDoI');
3655 if (LocalInfo == NULL)
3656 {
3657 return STATUS_INSUFFICIENT_RESOURCES;
3658 }
3659
3660 /* Query the DOS name */
3661 Status = IopQueryNameInternal(FileObject,
3662 TRUE,
3663 TRUE,
3664 LocalInfo,
3665 Length,
3666 &ReturnLength,
3667 KernelMode);
3668 /* If it succeed, nothing more to do */
3669 if (Status == STATUS_SUCCESS)
3670 {
3671 break;
3672 }
3673
3674 /* Otherwise, prepare for re-allocation */
3675 ExFreePoolWithTag(LocalInfo, 'nDoI');
3676
3677 /*
3678 * If we failed because of something else
3679 * than memory, simply stop and fail here
3680 */
3681 if (Status != STATUS_BUFFER_OVERFLOW)
3682 {
3683 return Status;
3684 }
3685 }
3686
3687 /* Success case here: return our buffer */
3688 *ObjectNameInformation = LocalInfo;
3689 return STATUS_SUCCESS;
3690 }
3691
3692 /*
3693 * @implemented
3694 */
3695 NTSTATUS
3696 NTAPI
3697 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
3698 IN BOOLEAN Remote)
3699 {
3700 NTSTATUS Status = STATUS_SUCCESS;
3701 BOOLEAN FlagSet;
3702
3703 /* Get the flag status */
3704 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3705
3706 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3707 if (Remote && !FlagSet)
3708 {
3709 /* Set the flag */
3710 FileObject->Flags |= FO_REMOTE_ORIGIN;
3711 }
3712 else if (!Remote && FlagSet)
3713 {
3714 /* Remove the flag */
3715 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
3716 }
3717 else
3718 {
3719 /* Fail */
3720 Status = STATUS_INVALID_PARAMETER_MIX;
3721 }
3722
3723 /* Return status */
3724 return Status;
3725 }
3726
3727 /*
3728 * @implemented
3729 */
3730 NTSTATUS
3731 NTAPI
3732 NtCreateFile(PHANDLE FileHandle,
3733 ACCESS_MASK DesiredAccess,
3734 POBJECT_ATTRIBUTES ObjectAttributes,
3735 PIO_STATUS_BLOCK IoStatusBlock,
3736 PLARGE_INTEGER AllocateSize,
3737 ULONG FileAttributes,
3738 ULONG ShareAccess,
3739 ULONG CreateDisposition,
3740 ULONG CreateOptions,
3741 PVOID EaBuffer,
3742 ULONG EaLength)
3743 {
3744 /* Call the I/O Function */
3745 return IoCreateFile(FileHandle,
3746 DesiredAccess,
3747 ObjectAttributes,
3748 IoStatusBlock,
3749 AllocateSize,
3750 FileAttributes,
3751 ShareAccess,
3752 CreateDisposition,
3753 CreateOptions,
3754 EaBuffer,
3755 EaLength,
3756 CreateFileTypeNone,
3757 NULL,
3758 0);
3759 }
3760
3761 NTSTATUS
3762 NTAPI
3763 NtCreateMailslotFile(OUT PHANDLE FileHandle,
3764 IN ACCESS_MASK DesiredAccess,
3765 IN POBJECT_ATTRIBUTES ObjectAttributes,
3766 OUT PIO_STATUS_BLOCK IoStatusBlock,
3767 IN ULONG CreateOptions,
3768 IN ULONG MailslotQuota,
3769 IN ULONG MaxMessageSize,
3770 IN PLARGE_INTEGER TimeOut)
3771 {
3772 MAILSLOT_CREATE_PARAMETERS Buffer;
3773 PAGED_CODE();
3774
3775 /* Check for Timeout */
3776 if (TimeOut)
3777 {
3778 /* check if the call came from user mode */
3779 if (KeGetPreviousMode() != KernelMode)
3780 {
3781 /* Enter SEH for Probe */
3782 _SEH2_TRY
3783 {
3784 /* Probe the timeout */
3785 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
3786 }
3787 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3788 {
3789 /* Return the exception code */
3790 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3791 }
3792 _SEH2_END;
3793 }
3794 else
3795 {
3796 /* Otherwise, capture directly */
3797 Buffer.ReadTimeout = *TimeOut;
3798 }
3799
3800 /* Set the correct setting */
3801 Buffer.TimeoutSpecified = TRUE;
3802 }
3803 else
3804 {
3805 /* Tell the FSD we don't have a timeout */
3806 Buffer.TimeoutSpecified = FALSE;
3807 }
3808
3809 /* Set Settings */
3810 Buffer.MailslotQuota = MailslotQuota;
3811 Buffer.MaximumMessageSize = MaxMessageSize;
3812
3813 /* Call I/O */
3814 return IoCreateFile(FileHandle,
3815 DesiredAccess,
3816 ObjectAttributes,
3817 IoStatusBlock,
3818 NULL,
3819 0,
3820 FILE_SHARE_READ | FILE_SHARE_WRITE,
3821 FILE_CREATE,
3822 CreateOptions,
3823 NULL,
3824 0,
3825 CreateFileTypeMailslot,
3826 (PVOID)&Buffer,
3827 0);
3828 }
3829
3830 NTSTATUS
3831 NTAPI
3832 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
3833 IN ACCESS_MASK DesiredAccess,
3834 IN POBJECT_ATTRIBUTES ObjectAttributes,
3835 OUT PIO_STATUS_BLOCK IoStatusBlock,
3836 IN ULONG ShareAccess,
3837 IN ULONG CreateDisposition,
3838 IN ULONG CreateOptions,
3839 IN ULONG NamedPipeType,
3840 IN ULONG ReadMode,
3841 IN ULONG CompletionMode,
3842 IN ULONG MaximumInstances,
3843 IN ULONG InboundQuota,
3844 IN ULONG OutboundQuota,
3845 IN PLARGE_INTEGER DefaultTimeout)
3846 {
3847 NAMED_PIPE_CREATE_PARAMETERS Buffer;
3848 PAGED_CODE();
3849
3850 /* Check for Timeout */
3851 if (DefaultTimeout)
3852 {
3853 /* check if the call came from user mode */
3854 if (KeGetPreviousMode() != KernelMode)
3855 {
3856 /* Enter SEH for Probe */
3857 _SEH2_TRY
3858 {
3859 /* Probe the timeout */
3860 Buffer.DefaultTimeout =
3861 ProbeForReadLargeInteger(DefaultTimeout);
3862 }
3863 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3864 {
3865 /* Return the exception code */
3866 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3867 }
3868 _SEH2_END;
3869 }
3870 else
3871 {
3872 /* Otherwise, capture directly */
3873 Buffer.DefaultTimeout = *DefaultTimeout;
3874 }
3875
3876 /* Set the correct setting */
3877 Buffer.TimeoutSpecified = TRUE;
3878 }
3879 else
3880 {
3881 /* Tell the FSD we don't have a timeout */
3882 Buffer.TimeoutSpecified = FALSE;
3883 }
3884
3885 /* Set Settings */
3886 Buffer.NamedPipeType = NamedPipeType;
3887 Buffer.ReadMode = ReadMode;
3888 Buffer.CompletionMode = CompletionMode;
3889 Buffer.MaximumInstances = MaximumInstances;
3890 Buffer.InboundQuota = InboundQuota;
3891 Buffer.OutboundQuota = OutboundQuota;
3892
3893 /* Call I/O */
3894 return IoCreateFile(FileHandle,
3895 DesiredAccess,
3896 ObjectAttributes,
3897 IoStatusBlock,
3898 NULL,
3899 0,
3900 ShareAccess,
3901 CreateDisposition,
3902 CreateOptions,
3903 NULL,
3904 0,
3905 CreateFileTypeNamedPipe,
3906 (PVOID)&Buffer,
3907 0);
3908 }
3909
3910 NTSTATUS
3911 NTAPI
3912 NtFlushWriteBuffer(VOID)
3913 {
3914 PAGED_CODE();
3915
3916 /* Call the kernel */
3917 KeFlushWriteBuffer();
3918 return STATUS_SUCCESS;
3919 }
3920
3921 /*
3922 * @implemented
3923 */
3924 NTSTATUS
3925 NTAPI
3926 NtOpenFile(OUT PHANDLE FileHandle,
3927 IN ACCESS_MASK DesiredAccess,
3928 IN POBJECT_ATTRIBUTES ObjectAttributes,
3929 OUT PIO_STATUS_BLOCK IoStatusBlock,
3930 IN ULONG ShareAccess,
3931 IN ULONG OpenOptions)
3932 {
3933 /* Call the I/O Function */
3934 return IoCreateFile(FileHandle,
3935 DesiredAccess,
3936 ObjectAttributes,
3937 IoStatusBlock,
3938 NULL,
3939 0,
3940 ShareAccess,
3941 FILE_OPEN,
3942 OpenOptions,
3943 NULL,
3944 0,
3945 CreateFileTypeNone,
3946 NULL,
3947 0);
3948 }
3949
3950 NTSTATUS
3951 NTAPI
3952 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3953 OUT PFILE_BASIC_INFORMATION FileInformation)
3954 {
3955 /* Call the internal helper API */
3956 return IopQueryAttributesFile(ObjectAttributes,
3957 FileBasicInformation,
3958 sizeof(FILE_BASIC_INFORMATION),
3959 FileInformation);
3960 }
3961
3962 NTSTATUS
3963 NTAPI
3964 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
3965 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
3966 {
3967 /* Call the internal helper API */
3968 return IopQueryAttributesFile(ObjectAttributes,
3969 FileNetworkOpenInformation,
3970 sizeof(FILE_NETWORK_OPEN_INFORMATION),
3971 FileInformation);
3972 }
3973
3974 /**
3975 * @name NtCancelIoFile
3976 *
3977 * Cancel all pending I/O operations in the current thread for specified
3978 * file object.
3979 *
3980 * @param FileHandle
3981 * Handle to file object to cancel requests for. No specific
3982 * access rights are needed.
3983 * @param IoStatusBlock
3984 * Pointer to status block which is filled with final completition
3985 * status on successful return.
3986 *
3987 * @return Status.
3988 *
3989 * @implemented
3990 */
3991 NTSTATUS
3992 NTAPI
3993 NtCancelIoFile(IN HANDLE FileHandle,
3994 OUT PIO_STATUS_BLOCK IoStatusBlock)
3995 {
3996 PFILE_OBJECT FileObject;
3997 PETHREAD Thread;
3998 PIRP Irp;
3999 KIRQL OldIrql;
4000 BOOLEAN OurIrpsInList = FALSE;
4001 LARGE_INTEGER Interval;
4002 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
4003 NTSTATUS Status;
4004 PLIST_ENTRY ListHead, NextEntry;
4005 PAGED_CODE();
4006 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
4007
4008 /* Check the previous mode */
4009 if (PreviousMode != KernelMode)
4010 {
4011 /* Enter SEH for probing */
4012 _SEH2_TRY
4013 {
4014 /* Probe the I/O Status Block */
4015 ProbeForWriteIoStatusBlock(IoStatusBlock);
4016 }
4017 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4018 {
4019 /* Return the exception code */
4020 _SEH2_YIELD(return _SEH2_GetExceptionCode());
4021 }
4022 _SEH2_END;
4023 }
4024
4025 /* Reference the file object */
4026 Status = ObReferenceObjectByHandle(FileHandle,
4027 0,
4028 IoFileObjectType,
4029 PreviousMode,
4030 (PVOID*)&FileObject,
4031 NULL);
4032 if (!NT_SUCCESS(Status)) return Status;
4033
4034 /* IRP cancellations are synchronized at APC_LEVEL. */
4035 KeRaiseIrql(APC_LEVEL, &OldIrql);
4036
4037 /* Get the current thread */
4038 Thread = PsGetCurrentThread();
4039
4040 /* Update the operation counts */
4041 IopUpdateOperationCount(IopOtherTransfer);
4042
4043 /* Loop the list */
4044 ListHead = &Thread->IrpList;
4045 NextEntry = ListHead->Flink;
4046 while (ListHead != NextEntry)
4047 {
4048 /* Get the IRP and check if the File Object matches */
4049 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4050 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4051 {
4052 /* Cancel this IRP and keep looping */
4053 IoCancelIrp(Irp);
4054 OurIrpsInList = TRUE;
4055 }
4056
4057 /* Go to the next entry */
4058 NextEntry = NextEntry->Flink;
4059 }
4060
4061 /* Lower the IRQL */
4062 KeLowerIrql(OldIrql);
4063
4064 /* Check if we had found an IRP */
4065 if (OurIrpsInList)
4066 {
4067 /* Setup a 10ms wait */
4068 Interval.QuadPart = -100000;
4069
4070 /* Start looping */
4071 while (OurIrpsInList)
4072 {
4073 /* Do the wait */
4074 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
4075 OurIrpsInList = FALSE;
4076
4077 /* Raise IRQL */
4078 KeRaiseIrql(APC_LEVEL, &OldIrql);
4079
4080 /* Now loop the list again */
4081 NextEntry = ListHead->Flink;
4082 while (NextEntry != ListHead)
4083 {
4084 /* Get the IRP and check if the File Object matches */
4085 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
4086 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
4087 {
4088 /* Keep looping */
4089 OurIrpsInList = TRUE;
4090 break;
4091 }
4092
4093 /* Go to the next entry */
4094 NextEntry = NextEntry->Flink;
4095 }
4096
4097 /* Lower the IRQL */
4098 KeLowerIrql(OldIrql);
4099 }
4100 }
4101
4102 /* Enter SEH for writing back the I/O Status */
4103 _SEH2_TRY
4104 {
4105 /* Write success */
4106 IoStatusBlock->Status = STATUS_SUCCESS;
4107 IoStatusBlock->Information = 0;
4108 }
4109 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
4110 {
4111 /* Ignore exception */
4112 }
4113 _SEH2_END;
4114
4115 /* Dereference the file object and return success */
4116 ObDereferenceObject(FileObject);
4117 return STATUS_SUCCESS;
4118 }
4119
4120 /*
4121 * @implemented
4122 */
4123 NTSTATUS
4124 NTAPI
4125 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
4126 {
4127 NTSTATUS Status;
4128 DUMMY_FILE_OBJECT LocalFileObject;
4129 HANDLE Handle;
4130 KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
4131 OPEN_PACKET OpenPacket;
4132 PAGED_CODE();
4133 IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
4134
4135 /* Setup the Open Packet */
4136 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
4137 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
4138 OpenPacket.Size = sizeof(OPEN_PACKET);
4139 OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
4140 OpenPacket.ShareAccess = FILE_SHARE_READ |
4141 FILE_SHARE_WRITE |
4142 FILE_SHARE_DELETE;
4143 OpenPacket.Disposition = FILE_OPEN;
4144 OpenPacket.DeleteOnly = TRUE;
4145 OpenPacket.LocalFileObject = &LocalFileObject;
4146
4147 /* Update the operation counts */
4148 IopUpdateOperationCount(IopOtherTransfer);
4149
4150 /*
4151 * Attempt opening the file. This will call the I/O Parse Routine for
4152 * the File Object (IopParseDevice) which will use the dummy file obejct
4153 * send the IRP to its device object. Note that we have two statuses
4154 * to worry about: the Object Manager's status (in Status) and the I/O
4155 * status, which is in the Open Packet's Final Status, and determined
4156 * by the Parse Check member.
4157 */
4158 Status = ObOpenObjectByName(ObjectAttributes,
4159 NULL,
4160 AccessMode,
4161 NULL,
4162 DELETE,
4163 &OpenPacket,
4164 &Handle);
4165 if (OpenPacket.ParseCheck == FALSE) return Status;
4166
4167 /* Retrn the Io status */
4168 return OpenPacket.FinalStatus;
4169 }
4170
4171 /* EOF */