[DRIVERS][NTOS][NDK] Use IO_STACK_LOCATION instead of EXTENDED_IO_STACK_LOCATION...
[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 IOTRACE(IO_FILE_DEBUG, "ObjectBody: %p\n", ObjectBody);
1942
1943 /* If this isn't the last handle for the current process, quit */
1944 if (HandleCount != 1) return;
1945
1946 /* Check if the file is locked and has more then one handle opened */
1947 if ((FileObject->LockOperation) && (SystemHandleCount != 1))
1948 {
1949 DPRINT1("We need to unlock this file!\n");
1950 ASSERT(FALSE);
1951 }
1952
1953 /* Make sure this is the last handle */
1954 if (SystemHandleCount != 1) return;
1955
1956 /* Check if this is a direct open or not */
1957 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1958 {
1959 /* Get the attached device */
1960 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1961 }
1962 else
1963 {
1964 /* Get the FO's device */
1965 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1966 }
1967
1968 /* Set the handle created flag */
1969 FileObject->Flags |= FO_HANDLE_CREATED;
1970
1971 /* Check if this is a sync FO and lock it */
1972 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopLockFileObject(FileObject);
1973
1974 /* Clear and set up Events */
1975 KeClearEvent(&FileObject->Event);
1976 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1977
1978 /* Allocate an IRP */
1979 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
1980
1981 /* Set it up */
1982 Irp->UserEvent = &Event;
1983 Irp->UserIosb = &Irp->IoStatus;
1984 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1985 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1986 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
1987 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
1988
1989 /* Set up Stack Pointer Data */
1990 StackPtr = IoGetNextIrpStackLocation(Irp);
1991 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
1992 StackPtr->FileObject = FileObject;
1993
1994 /* Queue the IRP */
1995 IopQueueIrpToThread(Irp);
1996
1997 /* Update operation counts */
1998 IopUpdateOperationCount(IopOtherTransfer);
1999
2000 /* Call the FS Driver */
2001 Status = IoCallDriver(DeviceObject, Irp);
2002 if (Status == STATUS_PENDING)
2003 {
2004 /* Wait for completion */
2005 KeWaitForSingleObject(&Event, UserRequest, KernelMode, FALSE, NULL);
2006 }
2007
2008 /* Unqueue the IRP */
2009 KeRaiseIrql(APC_LEVEL, &OldIrql);
2010 IopUnQueueIrpFromThread(Irp);
2011 KeLowerIrql(OldIrql);
2012
2013 /* Free the IRP */
2014 IoFreeIrp(Irp);
2015
2016 /* Release the lock if we were holding it */
2017 if (FileObject->Flags & FO_SYNCHRONOUS_IO) IopUnlockFileObject(FileObject);
2018 }
2019
2020 NTSTATUS
2021 NTAPI
2022 IopQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2023 IN FILE_INFORMATION_CLASS FileInformationClass,
2024 IN ULONG FileInformationSize,
2025 OUT PVOID FileInformation)
2026 {
2027 NTSTATUS Status;
2028 KPROCESSOR_MODE AccessMode = ExGetPreviousMode();
2029 DUMMY_FILE_OBJECT LocalFileObject;
2030 FILE_NETWORK_OPEN_INFORMATION NetworkOpenInfo;
2031 HANDLE Handle;
2032 OPEN_PACKET OpenPacket;
2033 BOOLEAN IsBasic;
2034 PAGED_CODE();
2035 IOTRACE(IO_FILE_DEBUG, "Class: %lx\n", FileInformationClass);
2036
2037 /* Check if the caller was user mode */
2038 if (AccessMode != KernelMode)
2039 {
2040 /* Protect probe in SEH */
2041 _SEH2_TRY
2042 {
2043 /* Probe the buffer */
2044 ProbeForWrite(FileInformation, FileInformationSize, sizeof(ULONG));
2045 }
2046 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2047 {
2048 /* Return the exception code */
2049 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2050 }
2051 _SEH2_END;
2052 }
2053
2054 /* Check if this is a basic or full request */
2055 IsBasic = (FileInformationSize == sizeof(FILE_BASIC_INFORMATION));
2056
2057 /* Setup the Open Packet */
2058 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2059 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2060 OpenPacket.Size = sizeof(OPEN_PACKET);
2061 OpenPacket.CreateOptions = FILE_OPEN_REPARSE_POINT;
2062 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2063 OpenPacket.Disposition = FILE_OPEN;
2064 OpenPacket.BasicInformation = IsBasic ? FileInformation : NULL;
2065 OpenPacket.NetworkInformation = IsBasic ? &NetworkOpenInfo :
2066 (AccessMode != KernelMode) ?
2067 &NetworkOpenInfo : FileInformation;
2068 OpenPacket.QueryOnly = TRUE;
2069 OpenPacket.FullAttributes = IsBasic ? FALSE : TRUE;
2070 OpenPacket.LocalFileObject = &LocalFileObject;
2071
2072 /* Update the operation count */
2073 IopUpdateOperationCount(IopOtherTransfer);
2074
2075 /*
2076 * Attempt opening the file. This will call the I/O Parse Routine for
2077 * the File Object (IopParseDevice) which will use the dummy file obejct
2078 * send the IRP to its device object. Note that we have two statuses
2079 * to worry about: the Object Manager's status (in Status) and the I/O
2080 * status, which is in the Open Packet's Final Status, and determined
2081 * by the Parse Check member.
2082 */
2083 Status = ObOpenObjectByName(ObjectAttributes,
2084 NULL,
2085 AccessMode,
2086 NULL,
2087 FILE_READ_ATTRIBUTES,
2088 &OpenPacket,
2089 &Handle);
2090 if (OpenPacket.ParseCheck == FALSE)
2091 {
2092 /* Parse failed */
2093 DPRINT("IopQueryAttributesFile failed for '%wZ' with 0x%lx\n",
2094 ObjectAttributes->ObjectName, Status);
2095 return Status;
2096 }
2097 else
2098 {
2099 /* Use the Io status */
2100 Status = OpenPacket.FinalStatus;
2101 }
2102
2103 /* Check if we were succesful and this was user mode and a full query */
2104 if ((NT_SUCCESS(Status)) && (AccessMode != KernelMode) && !(IsBasic))
2105 {
2106 /* Enter SEH for copy */
2107 _SEH2_TRY
2108 {
2109 /* Copy the buffer back */
2110 RtlCopyMemory(FileInformation,
2111 &NetworkOpenInfo,
2112 FileInformationSize);
2113 }
2114 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2115 {
2116 /* Get exception code */
2117 Status = _SEH2_GetExceptionCode();
2118 }
2119 _SEH2_END;
2120 }
2121
2122 /* Return status */
2123 return Status;
2124 }
2125
2126 PVOID
2127 NTAPI
2128 IoGetFileObjectFilterContext(IN PFILE_OBJECT FileObject)
2129 {
2130 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2131 {
2132 UNIMPLEMENTED;
2133 /* FIXME: return NULL for the moment ~ */
2134 return NULL;
2135 }
2136
2137 return NULL;
2138 }
2139
2140 NTSTATUS
2141 NTAPI
2142 IoChangeFileObjectFilterContext(IN PFILE_OBJECT FileObject,
2143 IN PVOID FilterContext,
2144 IN BOOLEAN Define)
2145 {
2146 if (!(FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION))
2147 {
2148 return STATUS_INVALID_PARAMETER;
2149 }
2150
2151 UNIMPLEMENTED;
2152
2153 return STATUS_NOT_IMPLEMENTED;
2154 }
2155
2156 NTSTATUS
2157 NTAPI
2158 IopCreateFile(OUT PHANDLE FileHandle,
2159 IN ACCESS_MASK DesiredAccess,
2160 IN POBJECT_ATTRIBUTES ObjectAttributes,
2161 OUT PIO_STATUS_BLOCK IoStatusBlock,
2162 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2163 IN ULONG FileAttributes,
2164 IN ULONG ShareAccess,
2165 IN ULONG Disposition,
2166 IN ULONG CreateOptions,
2167 IN PVOID EaBuffer OPTIONAL,
2168 IN ULONG EaLength,
2169 IN CREATE_FILE_TYPE CreateFileType,
2170 IN PVOID ExtraCreateParameters OPTIONAL,
2171 IN ULONG Options,
2172 IN ULONG Flags,
2173 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2174 {
2175 KPROCESSOR_MODE AccessMode;
2176 HANDLE LocalHandle = 0;
2177 LARGE_INTEGER SafeAllocationSize;
2178 NTSTATUS Status = STATUS_SUCCESS;
2179 PNAMED_PIPE_CREATE_PARAMETERS NamedPipeCreateParameters;
2180 POPEN_PACKET OpenPacket;
2181 ULONG EaErrorOffset;
2182 PAGED_CODE();
2183
2184 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2185
2186
2187 /* Check if we have no parameter checking to do */
2188 if (Options & IO_NO_PARAMETER_CHECKING)
2189 {
2190 /* Then force kernel-mode access to avoid checks */
2191 AccessMode = KernelMode;
2192 }
2193 else
2194 {
2195 /* Otherwise, use the actual mode */
2196 AccessMode = ExGetPreviousMode();
2197 }
2198
2199 /* Check if we need to do parameter checking */
2200 if ((AccessMode != KernelMode) || (Options & IO_CHECK_CREATE_PARAMETERS))
2201 {
2202 /* Validate parameters */
2203 if (FileAttributes & ~FILE_ATTRIBUTE_VALID_FLAGS)
2204 {
2205 DPRINT1("File Create 'FileAttributes' Parameter contains invalid flags!\n");
2206 return STATUS_INVALID_PARAMETER;
2207 }
2208
2209 if (ShareAccess & ~FILE_SHARE_VALID_FLAGS)
2210 {
2211 DPRINT1("File Create 'ShareAccess' Parameter contains invalid flags!\n");
2212 return STATUS_INVALID_PARAMETER;
2213 }
2214
2215 if (Disposition > FILE_MAXIMUM_DISPOSITION)
2216 {
2217 DPRINT1("File Create 'Disposition' Parameter is out of range!\n");
2218 return STATUS_INVALID_PARAMETER;
2219 }
2220
2221 if (CreateOptions & ~FILE_VALID_OPTION_FLAGS)
2222 {
2223 DPRINT1("File Create 'CreateOptions' parameter contains invalid flags!\n");
2224 return STATUS_INVALID_PARAMETER;
2225 }
2226
2227 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT)) &&
2228 (!(DesiredAccess & SYNCHRONIZE)))
2229 {
2230 DPRINT1("File Create 'CreateOptions' parameter FILE_SYNCHRONOUS_IO_* requested, but 'DesiredAccess' does not have SYNCHRONIZE!\n");
2231 return STATUS_INVALID_PARAMETER;
2232 }
2233
2234 if ((CreateOptions & FILE_DELETE_ON_CLOSE) && (!(DesiredAccess & DELETE)))
2235 {
2236 DPRINT1("File Create 'CreateOptions' parameter FILE_DELETE_ON_CLOSE requested, but 'DesiredAccess' does not have DELETE!\n");
2237 return STATUS_INVALID_PARAMETER;
2238 }
2239
2240 if ((CreateOptions & (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT)) ==
2241 (FILE_SYNCHRONOUS_IO_NONALERT | FILE_SYNCHRONOUS_IO_ALERT))
2242 {
2243 DPRINT1("File Create 'FileAttributes' parameter both FILE_SYNCHRONOUS_IO_NONALERT and FILE_SYNCHRONOUS_IO_ALERT specified!\n");
2244 return STATUS_INVALID_PARAMETER;
2245 }
2246
2247 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2248 (CreateOptions & ~(FILE_DIRECTORY_FILE |
2249 FILE_SYNCHRONOUS_IO_ALERT |
2250 FILE_SYNCHRONOUS_IO_NONALERT |
2251 FILE_WRITE_THROUGH |
2252 FILE_COMPLETE_IF_OPLOCKED |
2253 FILE_OPEN_FOR_BACKUP_INTENT |
2254 FILE_DELETE_ON_CLOSE |
2255 FILE_OPEN_FOR_FREE_SPACE_QUERY |
2256 FILE_OPEN_BY_FILE_ID |
2257 FILE_NO_COMPRESSION |
2258 FILE_OPEN_REPARSE_POINT)))
2259 {
2260 DPRINT1("File Create 'CreateOptions' Parameter has flags incompatible with FILE_DIRECTORY_FILE!\n");
2261 return STATUS_INVALID_PARAMETER;
2262 }
2263
2264 if ((CreateOptions & FILE_DIRECTORY_FILE) && !(CreateOptions & FILE_NON_DIRECTORY_FILE) &&
2265 (Disposition != FILE_CREATE) && (Disposition != FILE_OPEN) && (Disposition != FILE_OPEN_IF))
2266 {
2267 DPRINT1("File Create 'CreateOptions' Parameter FILE_DIRECTORY_FILE requested, but 'Disposition' is not FILE_CREATE/FILE_OPEN/FILE_OPEN_IF!\n");
2268 return STATUS_INVALID_PARAMETER;
2269 }
2270
2271 if ((CreateOptions & FILE_COMPLETE_IF_OPLOCKED) && (CreateOptions & FILE_RESERVE_OPFILTER))
2272 {
2273 DPRINT1("File Create 'CreateOptions' Parameter both FILE_COMPLETE_IF_OPLOCKED and FILE_RESERVE_OPFILTER specified!\n");
2274 return STATUS_INVALID_PARAMETER;
2275 }
2276
2277 if ((CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING) && (DesiredAccess & FILE_APPEND_DATA))
2278 {
2279 DPRINT1("File Create 'CreateOptions' parameter FILE_NO_INTERMEDIATE_BUFFERING requested, but 'DesiredAccess' FILE_APPEND_DATA requires it!\n");
2280 return STATUS_INVALID_PARAMETER;
2281 }
2282
2283 /* Now check if this is a named pipe */
2284 if (CreateFileType == CreateFileTypeNamedPipe)
2285 {
2286 /* Make sure we have extra parameters */
2287 if (!ExtraCreateParameters)
2288 {
2289 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2290 return STATUS_INVALID_PARAMETER;
2291 }
2292
2293 /* Get the parameters and validate them */
2294 NamedPipeCreateParameters = ExtraCreateParameters;
2295 if ((NamedPipeCreateParameters->NamedPipeType > FILE_PIPE_MESSAGE_TYPE) ||
2296 (NamedPipeCreateParameters->ReadMode > FILE_PIPE_MESSAGE_MODE) ||
2297 (NamedPipeCreateParameters->CompletionMode > FILE_PIPE_COMPLETE_OPERATION) ||
2298 (ShareAccess & FILE_SHARE_DELETE) ||
2299 ((Disposition < FILE_OPEN) || (Disposition > FILE_OPEN_IF)) ||
2300 (CreateOptions & ~FILE_VALID_PIPE_OPTION_FLAGS))
2301 {
2302 /* Invalid named pipe create */
2303 DPRINT1("Invalid named pipe create\n");
2304 return STATUS_INVALID_PARAMETER;
2305 }
2306 }
2307 else if (CreateFileType == CreateFileTypeMailslot)
2308 {
2309 /* Make sure we have extra parameters */
2310 if (!ExtraCreateParameters)
2311 {
2312 DPRINT1("Invalid parameter: ExtraCreateParameters == 0!\n");
2313 return STATUS_INVALID_PARAMETER;
2314 }
2315
2316 /* Get the parameters and validate them */
2317 if ((ShareAccess & FILE_SHARE_DELETE) ||
2318 !(ShareAccess & ~FILE_SHARE_WRITE) ||
2319 (Disposition != FILE_CREATE) ||
2320 (CreateOptions & ~FILE_VALID_MAILSLOT_OPTION_FLAGS))
2321 {
2322 /* Invalid mailslot create */
2323 DPRINT1("Invalid mailslot create\n");
2324 return STATUS_INVALID_PARAMETER;
2325 }
2326 }
2327 }
2328
2329 /* Allocate the open packet */
2330 OpenPacket = ExAllocatePoolWithTag(NonPagedPool, sizeof(*OpenPacket), 'pOoI');
2331 if (!OpenPacket) return STATUS_INSUFFICIENT_RESOURCES;
2332 RtlZeroMemory(OpenPacket, sizeof(*OpenPacket));
2333
2334 /* Check if the call came from user mode */
2335 if (AccessMode != KernelMode)
2336 {
2337 _SEH2_TRY
2338 {
2339 /* Probe the output parameters */
2340 ProbeForWriteHandle(FileHandle);
2341 ProbeForWriteIoStatusBlock(IoStatusBlock);
2342
2343 /* Probe the allocation size if one was passed in */
2344 if (AllocationSize)
2345 {
2346 SafeAllocationSize = ProbeForReadLargeInteger(AllocationSize);
2347 }
2348 else
2349 {
2350 SafeAllocationSize.QuadPart = 0;
2351 }
2352
2353 /* Make sure it's valid */
2354 if (SafeAllocationSize.QuadPart < 0)
2355 {
2356 RtlRaiseStatus(STATUS_INVALID_PARAMETER);
2357 }
2358
2359 /* Check if EA was passed in */
2360 if ((EaBuffer) && (EaLength))
2361 {
2362 /* Probe it */
2363 ProbeForRead(EaBuffer, EaLength, sizeof(ULONG));
2364
2365 /* And marshall it */
2366 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2367 EaLength,
2368 TAG_EA);
2369 OpenPacket->EaLength = EaLength;
2370 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2371
2372 /* Validate the buffer */
2373 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2374 EaLength,
2375 &EaErrorOffset);
2376 if (!NT_SUCCESS(Status))
2377 {
2378 /* Undo everything if it's invalid */
2379 DPRINT1("Invalid EA buffer\n");
2380 IoStatusBlock->Status = Status;
2381 IoStatusBlock->Information = EaErrorOffset;
2382 RtlRaiseStatus(Status);
2383 }
2384 }
2385 }
2386 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2387 {
2388 /* Return the exception code */
2389 if (OpenPacket->EaBuffer != NULL) ExFreePool(OpenPacket->EaBuffer);
2390 ExFreePool(OpenPacket);
2391 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2392 }
2393 _SEH2_END;
2394 }
2395 else
2396 {
2397 /* Check if this is a device attach */
2398 if (CreateOptions & IO_ATTACH_DEVICE_API)
2399 {
2400 /* Set the flag properly */
2401 Options |= IO_ATTACH_DEVICE;
2402 CreateOptions &= ~IO_ATTACH_DEVICE_API;
2403 }
2404
2405 /* Check if we have allocation size */
2406 if (AllocationSize)
2407 {
2408 /* Capture it */
2409 SafeAllocationSize = *AllocationSize;
2410 }
2411 else
2412 {
2413 /* Otherwise, no size */
2414 SafeAllocationSize.QuadPart = 0;
2415 }
2416
2417 /* Check if we have an EA packet */
2418 if ((EaBuffer) && (EaLength))
2419 {
2420 /* Allocate the kernel copy */
2421 OpenPacket->EaBuffer = ExAllocatePoolWithTag(NonPagedPool,
2422 EaLength,
2423 TAG_EA);
2424 if (!OpenPacket->EaBuffer)
2425 {
2426 ExFreePool(OpenPacket);
2427 DPRINT1("Failed to allocate open packet EA buffer\n");
2428 return STATUS_INSUFFICIENT_RESOURCES;
2429 }
2430
2431 /* Copy the data */
2432 OpenPacket->EaLength = EaLength;
2433 RtlCopyMemory(OpenPacket->EaBuffer, EaBuffer, EaLength);
2434
2435 /* Validate the buffer */
2436 Status = IoCheckEaBufferValidity(OpenPacket->EaBuffer,
2437 EaLength,
2438 &EaErrorOffset);
2439 if (!NT_SUCCESS(Status))
2440 {
2441 /* Undo everything if it's invalid */
2442 DPRINT1("Invalid EA buffer\n");
2443 ExFreePool(OpenPacket->EaBuffer);
2444 IoStatusBlock->Status = Status;
2445 IoStatusBlock->Information = EaErrorOffset;
2446 ExFreePool(OpenPacket);
2447 return Status;
2448 }
2449 }
2450 }
2451
2452 /* Setup the Open Packet */
2453 OpenPacket->Type = IO_TYPE_OPEN_PACKET;
2454 OpenPacket->Size = sizeof(*OpenPacket);
2455 OpenPacket->AllocationSize = SafeAllocationSize;
2456 OpenPacket->CreateOptions = CreateOptions;
2457 OpenPacket->FileAttributes = (USHORT)FileAttributes;
2458 OpenPacket->ShareAccess = (USHORT)ShareAccess;
2459 OpenPacket->Options = Options;
2460 OpenPacket->Disposition = Disposition;
2461 OpenPacket->CreateFileType = CreateFileType;
2462 OpenPacket->ExtraCreateParameters = ExtraCreateParameters;
2463 OpenPacket->InternalFlags = Flags;
2464 OpenPacket->TopDeviceObjectHint = DeviceObject;
2465
2466 /* Update the operation count */
2467 IopUpdateOperationCount(IopOtherTransfer);
2468
2469 /*
2470 * Attempt opening the file. This will call the I/O Parse Routine for
2471 * the File Object (IopParseDevice) which will create the object and
2472 * send the IRP to its device object. Note that we have two statuses
2473 * to worry about: the Object Manager's status (in Status) and the I/O
2474 * status, which is in the Open Packet's Final Status, and determined
2475 * by the Parse Check member.
2476 */
2477 Status = ObOpenObjectByName(ObjectAttributes,
2478 NULL,
2479 AccessMode,
2480 NULL,
2481 DesiredAccess,
2482 OpenPacket,
2483 &LocalHandle);
2484
2485 /* Free the EA Buffer */
2486 if (OpenPacket->EaBuffer) ExFreePool(OpenPacket->EaBuffer);
2487
2488 /* Now check for Ob or Io failure */
2489 if (!(NT_SUCCESS(Status)) || (OpenPacket->ParseCheck == FALSE))
2490 {
2491 /* Check if Ob thinks well went well */
2492 if (NT_SUCCESS(Status))
2493 {
2494 /*
2495 * Tell it otherwise. Because we didn't use an ObjectType,
2496 * it incorrectly returned us a handle to God knows what.
2497 */
2498 ZwClose(LocalHandle);
2499 Status = STATUS_OBJECT_TYPE_MISMATCH;
2500 }
2501
2502 /* Now check the Io status */
2503 if (!NT_SUCCESS(OpenPacket->FinalStatus))
2504 {
2505 /* Use this status instead of Ob's */
2506 Status = OpenPacket->FinalStatus;
2507
2508 /* Check if it was only a warning */
2509 if (NT_WARNING(Status))
2510 {
2511 /* Protect write with SEH */
2512 _SEH2_TRY
2513 {
2514 /* In this case, we copy the I/O Status back */
2515 IoStatusBlock->Information = OpenPacket->Information;
2516 IoStatusBlock->Status = OpenPacket->FinalStatus;
2517 }
2518 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2519 {
2520 /* Get exception code */
2521 Status = _SEH2_GetExceptionCode();
2522 }
2523 _SEH2_END;
2524 }
2525 }
2526 else if ((OpenPacket->FileObject) && (OpenPacket->ParseCheck == FALSE))
2527 {
2528 /*
2529 * This can happen in the very bizarre case where the parse routine
2530 * actually executed more then once (due to a reparse) and ended
2531 * up failing after already having created the File Object.
2532 */
2533 if (OpenPacket->FileObject->FileName.Length)
2534 {
2535 /* It had a name, free it */
2536 ExFreePoolWithTag(OpenPacket->FileObject->FileName.Buffer, TAG_IO_NAME);
2537 }
2538
2539 /* Clear the device object to invalidate the FO, and dereference */
2540 OpenPacket->FileObject->DeviceObject = NULL;
2541 ObDereferenceObject(OpenPacket->FileObject);
2542 }
2543 }
2544 else
2545 {
2546 /* We reached success and have a valid file handle */
2547 OpenPacket->FileObject->Flags |= FO_HANDLE_CREATED;
2548 ASSERT(OpenPacket->FileObject->Type == IO_TYPE_FILE);
2549
2550 /* Enter SEH for write back */
2551 _SEH2_TRY
2552 {
2553 /* Write back the handle and I/O Status */
2554 *FileHandle = LocalHandle;
2555 IoStatusBlock->Information = OpenPacket->Information;
2556 IoStatusBlock->Status = OpenPacket->FinalStatus;
2557
2558 /* Get the Io status */
2559 Status = OpenPacket->FinalStatus;
2560 }
2561 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2562 {
2563 /* Get the exception status */
2564 Status = _SEH2_GetExceptionCode();
2565 }
2566 _SEH2_END;
2567 }
2568
2569 /* Check if we were 100% successful */
2570 if ((OpenPacket->ParseCheck != FALSE) && (OpenPacket->FileObject))
2571 {
2572 /* Dereference the File Object */
2573 ObDereferenceObject(OpenPacket->FileObject);
2574 }
2575
2576 /* Return status */
2577 ExFreePool(OpenPacket);
2578 return Status;
2579 }
2580
2581 /* FUNCTIONS *****************************************************************/
2582
2583 /*
2584 * @unimplemented
2585 */
2586 NTSTATUS
2587 NTAPI
2588 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
2589 IN ULONG Length,
2590 IN BOOLEAN SetOperation)
2591 {
2592 UNIMPLEMENTED;
2593 return STATUS_NOT_IMPLEMENTED;
2594 }
2595
2596 /*
2597 * @unimplemented
2598 */
2599 NTSTATUS
2600 NTAPI
2601 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
2602 IN ULONG QuotaLength,
2603 OUT PULONG ErrorOffset)
2604 {
2605 UNIMPLEMENTED;
2606 return STATUS_NOT_IMPLEMENTED;
2607 }
2608
2609 /*
2610 * @implemented
2611 */
2612 NTSTATUS
2613 NTAPI
2614 IoCreateFile(OUT PHANDLE FileHandle,
2615 IN ACCESS_MASK DesiredAccess,
2616 IN POBJECT_ATTRIBUTES ObjectAttributes,
2617 OUT PIO_STATUS_BLOCK IoStatusBlock,
2618 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2619 IN ULONG FileAttributes,
2620 IN ULONG ShareAccess,
2621 IN ULONG Disposition,
2622 IN ULONG CreateOptions,
2623 IN PVOID EaBuffer OPTIONAL,
2624 IN ULONG EaLength,
2625 IN CREATE_FILE_TYPE CreateFileType,
2626 IN PVOID ExtraCreateParameters OPTIONAL,
2627 IN ULONG Options)
2628 {
2629 PAGED_CODE();
2630
2631 return IopCreateFile(FileHandle,
2632 DesiredAccess,
2633 ObjectAttributes,
2634 IoStatusBlock,
2635 AllocationSize,
2636 FileAttributes,
2637 ShareAccess,
2638 Disposition,
2639 CreateOptions,
2640 EaBuffer,
2641 EaLength,
2642 CreateFileType,
2643 ExtraCreateParameters,
2644 Options,
2645 0,
2646 NULL);
2647 }
2648
2649 /*
2650 * @unimplemented
2651 */
2652 NTSTATUS
2653 NTAPI
2654 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
2655 IN ACCESS_MASK DesiredAccess,
2656 IN POBJECT_ATTRIBUTES ObjectAttributes,
2657 OUT PIO_STATUS_BLOCK IoStatusBlock,
2658 IN PLARGE_INTEGER AllocationSize OPTIONAL,
2659 IN ULONG FileAttributes,
2660 IN ULONG ShareAccess,
2661 IN ULONG Disposition,
2662 IN ULONG CreateOptions,
2663 IN PVOID EaBuffer OPTIONAL,
2664 IN ULONG EaLength,
2665 IN CREATE_FILE_TYPE CreateFileType,
2666 IN PVOID ExtraCreateParameters OPTIONAL,
2667 IN ULONG Options,
2668 IN PVOID DeviceObject)
2669 {
2670 ULONG Flags = 0;
2671
2672 PAGED_CODE();
2673
2674 /* Check if we were passed a device to send the create request to*/
2675 if (DeviceObject)
2676 {
2677 /* We'll tag this request into a file object extension */
2678 Flags = (IOP_CREATE_FILE_OBJECT_EXTENSION | IOP_USE_TOP_LEVEL_DEVICE_HINT);
2679 }
2680
2681 return IopCreateFile(FileHandle,
2682 DesiredAccess,
2683 ObjectAttributes,
2684 IoStatusBlock,
2685 AllocationSize,
2686 FileAttributes,
2687 ShareAccess,
2688 Disposition,
2689 CreateOptions,
2690 EaBuffer,
2691 EaLength,
2692 CreateFileType,
2693 ExtraCreateParameters,
2694 Options | IO_NO_PARAMETER_CHECKING,
2695 Flags,
2696 DeviceObject);
2697 }
2698
2699 /*
2700 * @implemented
2701 */
2702 PFILE_OBJECT
2703 NTAPI
2704 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
2705 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
2706 OUT PHANDLE FileObjectHandle OPTIONAL)
2707 {
2708 PFILE_OBJECT CreatedFileObject;
2709 NTSTATUS Status;
2710 HANDLE FileHandle;
2711 OBJECT_ATTRIBUTES ObjectAttributes;
2712 PAGED_CODE();
2713 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2714
2715 /* Choose Device Object */
2716 if (FileObject) DeviceObject = FileObject->DeviceObject;
2717
2718 /* Reference the device object and initialize attributes */
2719 InterlockedIncrement(&DeviceObject->ReferenceCount);
2720 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2721
2722 /* Create the File Object */
2723 Status = ObCreateObject(KernelMode,
2724 IoFileObjectType,
2725 &ObjectAttributes,
2726 KernelMode,
2727 NULL,
2728 sizeof(FILE_OBJECT),
2729 sizeof(FILE_OBJECT),
2730 0,
2731 (PVOID*)&CreatedFileObject);
2732 if (!NT_SUCCESS(Status))
2733 {
2734 /* Fail */
2735 IopDereferenceDeviceObject(DeviceObject, FALSE);
2736 ExRaiseStatus(Status);
2737 }
2738
2739 /* Set File Object Data */
2740 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2741 CreatedFileObject->DeviceObject = DeviceObject;
2742 CreatedFileObject->Type = IO_TYPE_FILE;
2743 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2744 CreatedFileObject->Flags = FO_STREAM_FILE;
2745
2746 /* Initialize the wait event */
2747 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2748
2749 /* Insert it to create a handle for it */
2750 Status = ObInsertObject(CreatedFileObject,
2751 NULL,
2752 FILE_READ_DATA,
2753 1,
2754 (PVOID*)&CreatedFileObject,
2755 &FileHandle);
2756 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
2757
2758 /* Set the handle created flag */
2759 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2760 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2761
2762 /* Check if we have a VPB */
2763 if (DeviceObject->Vpb)
2764 {
2765 /* Reference it */
2766 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2767 }
2768
2769 /* Check if the caller wants the handle */
2770 if (FileObjectHandle)
2771 {
2772 /* Return it */
2773 *FileObjectHandle = FileHandle;
2774 ObDereferenceObject(CreatedFileObject);
2775 }
2776 else
2777 {
2778 /* Otherwise, close it */
2779 ObCloseHandle(FileHandle, KernelMode);
2780 }
2781
2782 /* Return the file object */
2783 return CreatedFileObject;
2784 }
2785
2786 /*
2787 * @implemented
2788 */
2789 PFILE_OBJECT
2790 NTAPI
2791 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
2792 IN PDEVICE_OBJECT DeviceObject)
2793 {
2794 /* Call the newer function */
2795 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
2796 }
2797
2798 /*
2799 * @implemented
2800 */
2801 PFILE_OBJECT
2802 NTAPI
2803 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
2804 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2805 {
2806 PFILE_OBJECT CreatedFileObject;
2807 NTSTATUS Status;
2808 OBJECT_ATTRIBUTES ObjectAttributes;
2809 PAGED_CODE();
2810 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2811
2812 /* Choose Device Object */
2813 if (FileObject) DeviceObject = FileObject->DeviceObject;
2814
2815 /* Reference the device object and initialize attributes */
2816 InterlockedIncrement(&DeviceObject->ReferenceCount);
2817 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2818
2819 /* Create the File Object */
2820 Status = ObCreateObject(KernelMode,
2821 IoFileObjectType,
2822 &ObjectAttributes,
2823 KernelMode,
2824 NULL,
2825 sizeof(FILE_OBJECT),
2826 sizeof(FILE_OBJECT),
2827 0,
2828 (PVOID*)&CreatedFileObject);
2829 if (!NT_SUCCESS(Status))
2830 {
2831 /* Fail */
2832 IopDereferenceDeviceObject(DeviceObject, FALSE);
2833 ExRaiseStatus(Status);
2834 }
2835
2836 /* Set File Object Data */
2837 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2838 CreatedFileObject->DeviceObject = DeviceObject;
2839 CreatedFileObject->Type = IO_TYPE_FILE;
2840 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2841 CreatedFileObject->Flags = FO_STREAM_FILE;
2842
2843 /* Initialize the wait event */
2844 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2845
2846 /* Destroy create information */
2847 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
2848 ObjectCreateInfo);
2849 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
2850
2851 /* Set the handle created flag */
2852 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2853 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2854
2855 /* Check if we have a VPB */
2856 if (DeviceObject->Vpb)
2857 {
2858 /* Reference it */
2859 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2860 }
2861
2862 /* Return the file object */
2863 return CreatedFileObject;
2864 }
2865
2866 /*
2867 * @implemented
2868 */
2869 PGENERIC_MAPPING
2870 NTAPI
2871 IoGetFileObjectGenericMapping(VOID)
2872 {
2873 /* Return the mapping */
2874 return &IopFileMapping;
2875 }
2876
2877 /*
2878 * @implemented
2879 */
2880 BOOLEAN
2881 NTAPI
2882 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
2883 {
2884 /* Return the flag status */
2885 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2886 }
2887
2888 /*
2889 * @implemented
2890 */
2891 BOOLEAN
2892 NTAPI
2893 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
2894 IN ACCESS_MASK DesiredAccess,
2895 IN ULONG OpenOptions,
2896 OUT PIO_STATUS_BLOCK IoStatus,
2897 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
2898 {
2899 NTSTATUS Status;
2900 DUMMY_FILE_OBJECT LocalFileObject;
2901 HANDLE Handle;
2902 OPEN_PACKET OpenPacket;
2903 PAGED_CODE();
2904 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2905
2906 /* Setup the Open Packet */
2907 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2908 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2909 OpenPacket.Size = sizeof(OPEN_PACKET);
2910 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
2911 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2912 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
2913 OpenPacket.Disposition = FILE_OPEN;
2914 OpenPacket.NetworkInformation = Buffer;
2915 OpenPacket.QueryOnly = TRUE;
2916 OpenPacket.FullAttributes = TRUE;
2917 OpenPacket.LocalFileObject = &LocalFileObject;
2918
2919 /*
2920 * Attempt opening the file. This will call the I/O Parse Routine for
2921 * the File Object (IopParseDevice) which will use the dummy file obejct
2922 * send the IRP to its device object. Note that we have two statuses
2923 * to worry about: the Object Manager's status (in Status) and the I/O
2924 * status, which is in the Open Packet's Final Status, and determined
2925 * by the Parse Check member.
2926 */
2927 Status = ObOpenObjectByName(ObjectAttributes,
2928 NULL,
2929 KernelMode,
2930 NULL,
2931 DesiredAccess,
2932 &OpenPacket,
2933 &Handle);
2934 if (OpenPacket.ParseCheck == FALSE)
2935 {
2936 /* Parse failed */
2937 IoStatus->Status = Status;
2938 }
2939 else
2940 {
2941 /* Use the Io status */
2942 IoStatus->Status = OpenPacket.FinalStatus;
2943 IoStatus->Information = OpenPacket.Information;
2944 }
2945
2946 /* Return success */
2947 return TRUE;
2948 }
2949
2950 /*
2951 * @implemented
2952 */
2953 VOID
2954 NTAPI
2955 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
2956 OUT PSHARE_ACCESS ShareAccess)
2957 {
2958 PAGED_CODE();
2959
2960 /* Check if the file has an extension */
2961 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2962 {
2963 /* Check if caller specified to ignore access checks */
2964 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2965 {
2966 /* Don't update share access */
2967 return;
2968 }
2969 }
2970
2971 /* Otherwise, check if there's any access present */
2972 if ((FileObject->ReadAccess) ||
2973 (FileObject->WriteAccess) ||
2974 (FileObject->DeleteAccess))
2975 {
2976 /* Increase the open count */
2977 ShareAccess->OpenCount++;
2978
2979 /* Add new share access */
2980 ShareAccess->Readers += FileObject->ReadAccess;
2981 ShareAccess->Writers += FileObject->WriteAccess;
2982 ShareAccess->Deleters += FileObject->DeleteAccess;
2983 ShareAccess->SharedRead += FileObject->SharedRead;
2984 ShareAccess->SharedWrite += FileObject->SharedWrite;
2985 ShareAccess->SharedDelete += FileObject->SharedDelete;
2986 }
2987 }
2988
2989 /*
2990 * @implemented
2991 */
2992 NTSTATUS
2993 NTAPI
2994 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
2995 IN ULONG DesiredShareAccess,
2996 IN PFILE_OBJECT FileObject,
2997 IN PSHARE_ACCESS ShareAccess,
2998 IN BOOLEAN Update)
2999 {
3000 BOOLEAN ReadAccess;
3001 BOOLEAN WriteAccess;
3002 BOOLEAN DeleteAccess;
3003 BOOLEAN SharedRead;
3004 BOOLEAN SharedWrite;
3005 BOOLEAN SharedDelete;
3006 PAGED_CODE();
3007
3008 /* Get access masks */
3009 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3010 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3011 DeleteAccess = (DesiredAccess & DELETE) != 0;
3012
3013 /* Set them in the file object */
3014 FileObject->ReadAccess = ReadAccess;
3015 FileObject->WriteAccess = WriteAccess;
3016 FileObject->DeleteAccess = DeleteAccess;
3017
3018 /* Check if the file has an extension */
3019 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3020 {
3021 /* Check if caller specified to ignore access checks */
3022 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3023 {
3024 /* Don't check share access */
3025 return STATUS_SUCCESS;
3026 }
3027 }
3028
3029 /* Check if we have any access */
3030 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
3031 {
3032 /* Get shared access masks */
3033 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3034 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3035 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3036
3037 /* Set them */
3038 FileObject->SharedRead = SharedRead;
3039 FileObject->SharedWrite = SharedWrite;
3040 FileObject->SharedDelete = SharedDelete;
3041
3042 /* Check if the shared access is violated */
3043 if ((ReadAccess &&
3044 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
3045 (WriteAccess &&
3046 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
3047 (DeleteAccess &&
3048 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
3049 ((ShareAccess->Readers != 0) && !SharedRead) ||
3050 ((ShareAccess->Writers != 0) && !SharedWrite) ||
3051 ((ShareAccess->Deleters != 0) && !SharedDelete))
3052 {
3053 /* Sharing violation, fail */
3054 return STATUS_SHARING_VIOLATION;
3055 }
3056
3057 /* It's not, check if caller wants us to update it */
3058 if (Update)
3059 {
3060 /* Increase open count */
3061 ShareAccess->OpenCount++;
3062
3063 /* Update shared access */
3064 ShareAccess->Readers += ReadAccess;
3065 ShareAccess->Writers += WriteAccess;
3066 ShareAccess->Deleters += DeleteAccess;
3067 ShareAccess->SharedRead += SharedRead;
3068 ShareAccess->SharedWrite += SharedWrite;
3069 ShareAccess->SharedDelete += SharedDelete;
3070 }
3071 }
3072
3073 /* Validation successful */
3074 return STATUS_SUCCESS;
3075 }
3076
3077 /*
3078 * @implemented
3079 */
3080 VOID
3081 NTAPI
3082 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
3083 IN PSHARE_ACCESS ShareAccess)
3084 {
3085 PAGED_CODE();
3086
3087 /* Check if the file has an extension */
3088 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3089 {
3090 /* Check if caller specified to ignore access checks */
3091 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3092 {
3093 /* Don't update share access */
3094 return;
3095 }
3096 }
3097
3098 /* Otherwise, check if there's any access present */
3099 if ((FileObject->ReadAccess) ||
3100 (FileObject->WriteAccess) ||
3101 (FileObject->DeleteAccess))
3102 {
3103 /* Decrement the open count */
3104 ShareAccess->OpenCount--;
3105
3106 /* Remove share access */
3107 ShareAccess->Readers -= FileObject->ReadAccess;
3108 ShareAccess->Writers -= FileObject->WriteAccess;
3109 ShareAccess->Deleters -= FileObject->DeleteAccess;
3110 ShareAccess->SharedRead -= FileObject->SharedRead;
3111 ShareAccess->SharedWrite -= FileObject->SharedWrite;
3112 ShareAccess->SharedDelete -= FileObject->SharedDelete;
3113 }
3114 }
3115
3116 /*
3117 * @implemented
3118 */
3119 VOID
3120 NTAPI
3121 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
3122 IN ULONG DesiredShareAccess,
3123 IN PFILE_OBJECT FileObject,
3124 OUT PSHARE_ACCESS ShareAccess)
3125 {
3126 BOOLEAN ReadAccess;
3127 BOOLEAN WriteAccess;
3128 BOOLEAN DeleteAccess;
3129 BOOLEAN SharedRead;
3130 BOOLEAN SharedWrite;
3131 BOOLEAN SharedDelete;
3132 BOOLEAN Update = TRUE;
3133 PAGED_CODE();
3134
3135 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
3136 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
3137 DeleteAccess = (DesiredAccess & DELETE) != 0;
3138
3139 /* Check if the file has an extension */
3140 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
3141 {
3142 /* Check if caller specified to ignore access checks */
3143 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
3144 {
3145 /* Don't update share access */
3146 Update = FALSE;
3147 }
3148 }
3149
3150 /* Update basic access */
3151 FileObject->ReadAccess = ReadAccess;
3152 FileObject->WriteAccess = WriteAccess;
3153 FileObject->DeleteAccess = DeleteAccess;
3154
3155 /* Check if we have no access as all */
3156 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
3157 {
3158 /* Check if we need to update the structure */
3159 if (!Update) return;
3160
3161 /* Otherwise, clear data */
3162 ShareAccess->OpenCount = 0;
3163 ShareAccess->Readers = 0;
3164 ShareAccess->Writers = 0;
3165 ShareAccess->Deleters = 0;
3166 ShareAccess->SharedRead = 0;
3167 ShareAccess->SharedWrite = 0;
3168 ShareAccess->SharedDelete = 0;
3169 }
3170 else
3171 {
3172 /* Calculate shared access */
3173 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
3174 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
3175 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
3176
3177 /* Set it in the FO */
3178 FileObject->SharedRead = SharedRead;
3179 FileObject->SharedWrite = SharedWrite;
3180 FileObject->SharedDelete = SharedDelete;
3181
3182 /* Check if we need to update the structure */
3183 if (!Update) return;
3184
3185 /* Otherwise, set data */
3186 ShareAccess->OpenCount = 1;
3187 ShareAccess->Readers = ReadAccess;
3188 ShareAccess->Writers = WriteAccess;
3189 ShareAccess->Deleters = DeleteAccess;
3190 ShareAccess->SharedRead = SharedRead;
3191 ShareAccess->SharedWrite = SharedWrite;
3192 ShareAccess->SharedDelete = SharedDelete;
3193 }
3194 }
3195
3196 /*
3197 * @implemented
3198 */
3199 VOID
3200 NTAPI
3201 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
3202 IN PFILE_OBJECT FileObject)
3203 {
3204 PIRP Irp;
3205 KEVENT Event;
3206 KIRQL OldIrql;
3207 NTSTATUS Status;
3208 PIO_STACK_LOCATION Stack;
3209
3210 /* Check if handles were already created for the
3211 * open file. If so, that's over.
3212 */
3213 if (FileObject->Flags & FO_HANDLE_CREATED)
3214 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
3215 (ULONG_PTR)FileObject,
3216 (ULONG_PTR)DeviceObject, 0, 0);
3217
3218 /* Reset the events */
3219 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
3220 KeClearEvent(&FileObject->Event);
3221
3222 /* Allocate the IRP we'll use */
3223 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
3224 /* Properly set it */
3225 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
3226 Irp->UserEvent = &Event;
3227 Irp->UserIosb = &Irp->IoStatus;
3228 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
3229 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3230 Irp->RequestorMode = KernelMode;
3231 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
3232
3233 Stack = IoGetNextIrpStackLocation(Irp);
3234 Stack->MajorFunction = IRP_MJ_CLEANUP;
3235 Stack->FileObject = FileObject;
3236
3237 /* Put on top of IRPs list of the thread */
3238 IopQueueIrpToThread(Irp);
3239
3240 /* Call the driver */
3241 Status = IoCallDriver(DeviceObject, Irp);
3242 if (Status == STATUS_PENDING)
3243 {
3244 KeWaitForSingleObject(&Event, UserRequest,
3245 KernelMode, FALSE, NULL);
3246 }
3247
3248 /* Remove from IRPs list */
3249 KeRaiseIrql(APC_LEVEL, &OldIrql);
3250 IopUnQueueIrpFromThread(Irp);
3251 KeLowerIrql(OldIrql);
3252
3253 /* Free the IRP */
3254 IoFreeIrp(Irp);
3255
3256 /* Clear the event */
3257 KeClearEvent(&FileObject->Event);
3258 /* And finally, mark the open operation as canceled */
3259 FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
3260 }
3261
3262 /*
3263 * @unimplemented
3264 */
3265 NTSTATUS
3266 NTAPI
3267 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
3268 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
3269 {
3270 UNIMPLEMENTED;
3271 return STATUS_NOT_IMPLEMENTED;
3272 }
3273
3274 /*
3275 * @implemented
3276 */
3277 NTSTATUS
3278 NTAPI
3279 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
3280 IN BOOLEAN Remote)
3281 {
3282 NTSTATUS Status = STATUS_SUCCESS;
3283 BOOLEAN FlagSet;
3284
3285 /* Get the flag status */
3286 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
3287
3288 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
3289 if (Remote && !FlagSet)
3290 {
3291 /* Set the flag */
3292 FileObject->Flags |= FO_REMOTE_ORIGIN;
3293 }
3294 else if (!Remote && FlagSet)
3295 {
3296 /* Remove the flag */
3297 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
3298 }
3299 else
3300 {
3301 /* Fail */
3302 Status = STATUS_INVALID_PARAMETER_MIX;
3303 }
3304
3305 /* Return status */
3306 return Status;
3307 }
3308
3309 /*
3310 * @implemented
3311 */
3312 NTSTATUS
3313 NTAPI
3314 NtCreateFile(PHANDLE FileHandle,
3315 ACCESS_MASK DesiredAccess,
3316 POBJECT_ATTRIBUTES ObjectAttributes,
3317 PIO_STATUS_BLOCK IoStatusBlock,
3318 PLARGE_INTEGER AllocateSize,
3319 ULONG FileAttributes,
3320 ULONG ShareAccess,
3321 ULONG CreateDisposition,
3322 ULONG CreateOptions,
3323 PVOID EaBuffer,
3324 ULONG EaLength)
3325 {
3326 /* Call the I/O Function */
3327 return IoCreateFile(FileHandle,
3328 DesiredAccess,
3329 ObjectAttributes,
3330 IoStatusBlock,
3331 AllocateSize,
3332 FileAttributes,
3333 ShareAccess,
3334 CreateDisposition,
3335 CreateOptions,
3336 EaBuffer,
3337 EaLength,
3338 CreateFileTypeNone,
3339 NULL,
3340 0);
3341 }
3342
3343 NTSTATUS
3344 NTAPI
3345 NtCreateMailslotFile(OUT PHANDLE FileHandle,
3346 IN ACCESS_MASK DesiredAccess,
3347 IN POBJECT_ATTRIBUTES ObjectAttributes,
3348 OUT PIO_STATUS_BLOCK IoStatusBlock,
3349 IN ULONG CreateOptions,
3350 IN ULONG MailslotQuota,
3351 IN ULONG MaxMessageSize,
3352 IN PLARGE_INTEGER TimeOut)
3353 {
3354 MAILSLOT_CREATE_PARAMETERS Buffer;
3355 PAGED_CODE();
3356
3357 /* Check for Timeout */
3358 if (TimeOut)
3359 {
3360 /* check if the call came from user mode */
3361 if (KeGetPreviousMode() != KernelMode)
3362 {
3363 /* Enter SEH for Probe */
3364 _SEH2_TRY
3365 {
3366 /* Probe the timeout */
3367 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
3368 }
3369 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3370 {
3371 /* Return the exception code */
3372 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3373 }
3374 _SEH2_END;
3375 }
3376 else
3377 {
3378 /* Otherwise, capture directly */
3379 Buffer.ReadTimeout = *TimeOut;
3380 }
3381
3382 /* Set the correct setting */
3383 Buffer.TimeoutSpecified = TRUE;
3384 }
3385 else
3386 {
3387 /* Tell the FSD we don't have a timeout */
3388 Buffer.TimeoutSpecified = FALSE;
3389 }
3390
3391 /* Set Settings */
3392 Buffer.MailslotQuota = MailslotQuota;
3393 Buffer.MaximumMessageSize = MaxMessageSize;
3394
3395 /* Call I/O */
3396 return IoCreateFile(FileHandle,
3397 DesiredAccess,
3398 ObjectAttributes,
3399 IoStatusBlock,
3400 NULL,
3401 0,
3402 FILE_SHARE_READ | FILE_SHARE_WRITE,
3403 FILE_CREATE,
3404 CreateOptions,
3405 NULL,
3406 0,
3407 CreateFileTypeMailslot,
3408 (PVOID)&Buffer,
3409 0);
3410 }
3411
3412 NTSTATUS
3413 NTAPI
3414 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
3415 IN ACCESS_MASK DesiredAccess,
3416 IN POBJECT_ATTRIBUTES ObjectAttributes,
3417 OUT PIO_STATUS_BLOCK IoStatusBlock,
3418 IN ULONG ShareAccess,
3419 IN ULONG CreateDisposition,
3420 IN ULONG CreateOptions,
3421 IN ULONG NamedPipeType,
3422 IN ULONG ReadMode,
3423 IN ULONG CompletionMode,
3424 IN ULONG MaximumInstances,
3425 IN ULONG InboundQuota,
3426 IN ULONG OutboundQuota,
3427 IN PLARGE_INTEGER DefaultTimeout)
3428 {
3429 NAMED_PIPE_CREATE_PARAMETERS Buffer;
3430 PAGED_CODE();
3431
3432 /* Check for Timeout */
3433 if (DefaultTimeout)
3434 {
3435 /* check if the call came from user mode */
3436 if (KeGetPreviousMode() != KernelMode)
3437 {
3438 /* Enter SEH for Probe */
3439 _SEH2_TRY
3440 {
3441 /* Probe the timeout */
3442 Buffer.DefaultTimeout =
3443 ProbeForReadLargeInteger(DefaultTimeout);
3444 }
3445 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
3446 {
3447 /* Return the exception code */
3448 _SEH2_YIELD(return _SEH2_GetExceptionCode());
3449 }
3450 _SEH2_END;
3451 }
3452 else
3453 {
3454 /* Otherwise, capture directly */
3455 Buffer.DefaultTimeout = *DefaultTimeout;
3456 }
3457
3458 /* Set the correct setting */
3459 Buffer.TimeoutSpecified = TRUE;
3460 }
3461 else
3462 {
3463 /* Tell the FSD we don't have a timeout */
3464 Buffer.TimeoutSpecified = FALSE;
3465 }
3466
3467 /* Set Settings */
3468 Buffer.NamedPipeType = NamedPipeType;
3469 Buffer.ReadMode = ReadMode;
3470 Buffer.CompletionMode = CompletionMode;
3471 Buffer.MaximumInstances = MaximumInstances;
3472 Buffer.InboundQuota = InboundQuota;
3473 Buffer.OutboundQuota = OutboundQuota;
3474
3475 /* Call I/O */
3476 return IoCreateFile(FileHandle,
3477 DesiredAccess,
3478 ObjectAttributes,
3479 IoStatusBlock,
3480 NULL,
3481 0,
3482 ShareAccess,
3483 CreateDisposition,
3484 CreateOptions,