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