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