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