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