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