Sync with trunk r58687.
[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.OriginalAttributes = *ObjectAttributes;
1844 OpenPacket.AllocationSize = SafeAllocationSize;
1845 OpenPacket.CreateOptions = CreateOptions;
1846 OpenPacket.FileAttributes = (USHORT)FileAttributes;
1847 OpenPacket.ShareAccess = (USHORT)ShareAccess;
1848 OpenPacket.EaBuffer = SystemEaBuffer;
1849 OpenPacket.EaLength = EaLength;
1850 OpenPacket.Options = Options;
1851 OpenPacket.Disposition = Disposition;
1852 OpenPacket.CreateFileType = CreateFileType;
1853 OpenPacket.MailslotOrPipeParameters = ExtraCreateParameters;
1854
1855 /* Update the operation count */
1856 IopUpdateOperationCount(IopOtherTransfer);
1857
1858 /*
1859 * Attempt opening the file. This will call the I/O Parse Routine for
1860 * the File Object (IopParseDevice) which will create the object and
1861 * send the IRP to its device object. Note that we have two statuses
1862 * to worry about: the Object Manager's status (in Status) and the I/O
1863 * status, which is in the Open Packet's Final Status, and determined
1864 * by the Parse Check member.
1865 */
1866 Status = ObOpenObjectByName(ObjectAttributes,
1867 NULL,
1868 AccessMode,
1869 NULL,
1870 DesiredAccess,
1871 &OpenPacket,
1872 &LocalHandle);
1873
1874 /* Free the EA Buffer */
1875 if (OpenPacket.EaBuffer) ExFreePool(OpenPacket.EaBuffer);
1876
1877 /* Now check for Ob or Io failure */
1878 if (!(NT_SUCCESS(Status)) || (OpenPacket.ParseCheck != TRUE))
1879 {
1880 /* Check if Ob thinks well went well */
1881 if (NT_SUCCESS(Status))
1882 {
1883 /*
1884 * Tell it otherwise. Because we didn't use an ObjectType,
1885 * it incorrectly returned us a handle to God knows what.
1886 */
1887 ZwClose(LocalHandle);
1888 Status = STATUS_OBJECT_TYPE_MISMATCH;
1889 }
1890
1891 /* Now check the Io status */
1892 if (!NT_SUCCESS(OpenPacket.FinalStatus))
1893 {
1894 /* Use this status instead of Ob's */
1895 Status = OpenPacket.FinalStatus;
1896
1897 /* Check if it was only a warning */
1898 if (NT_WARNING(Status))
1899 {
1900 /* Protect write with SEH */
1901 _SEH2_TRY
1902 {
1903 /* In this case, we copy the I/O Status back */
1904 IoStatusBlock->Information = OpenPacket.Information;
1905 IoStatusBlock->Status = OpenPacket.FinalStatus;
1906 }
1907 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1908 {
1909 /* Get exception code */
1910 Status = _SEH2_GetExceptionCode();
1911 }
1912 _SEH2_END;
1913 }
1914 }
1915 else if ((OpenPacket.FileObject) && (OpenPacket.ParseCheck != 1))
1916 {
1917 /*
1918 * This can happen in the very bizarre case where the parse routine
1919 * actually executed more then once (due to a reparse) and ended
1920 * up failing after already having created the File Object.
1921 */
1922 if (OpenPacket.FileObject->FileName.Length)
1923 {
1924 /* It had a name, free it */
1925 ExFreePoolWithTag(OpenPacket.FileObject->FileName.Buffer, TAG_IO_NAME);
1926 }
1927
1928 /* Clear the device object to invalidate the FO, and dereference */
1929 OpenPacket.FileObject->DeviceObject = NULL;
1930 ObDereferenceObject(OpenPacket.FileObject);
1931 }
1932 }
1933 else
1934 {
1935 /* We reached success and have a valid file handle */
1936 OpenPacket.FileObject->Flags |= FO_HANDLE_CREATED;
1937
1938 /* Enter SEH for write back */
1939 _SEH2_TRY
1940 {
1941 /* Write back the handle and I/O Status */
1942 *FileHandle = LocalHandle;
1943 IoStatusBlock->Information = OpenPacket.Information;
1944 IoStatusBlock->Status = OpenPacket.FinalStatus;
1945
1946 /* Get the Io status */
1947 Status = OpenPacket.FinalStatus;
1948 }
1949 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1950 {
1951 /* Get the exception status */
1952 Status = _SEH2_GetExceptionCode();
1953 }
1954 _SEH2_END;
1955 }
1956
1957 /* Check if we were 100% successful */
1958 if ((OpenPacket.ParseCheck == TRUE) && (OpenPacket.FileObject))
1959 {
1960 /* Dereference the File Object */
1961 ObDereferenceObject(OpenPacket.FileObject);
1962 }
1963
1964 /* Return status */
1965 return Status;
1966 }
1967
1968 /*
1969 * @unimplemented
1970 */
1971 NTSTATUS
1972 NTAPI
1973 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
1974 IN ACCESS_MASK DesiredAccess,
1975 IN POBJECT_ATTRIBUTES ObjectAttributes,
1976 OUT PIO_STATUS_BLOCK IoStatusBlock,
1977 IN PLARGE_INTEGER AllocationSize OPTIONAL,
1978 IN ULONG FileAttributes,
1979 IN ULONG ShareAccess,
1980 IN ULONG Disposition,
1981 IN ULONG CreateOptions,
1982 IN PVOID EaBuffer OPTIONAL,
1983 IN ULONG EaLength,
1984 IN CREATE_FILE_TYPE CreateFileType,
1985 IN PVOID ExtraCreateParameters OPTIONAL,
1986 IN ULONG Options,
1987 IN PVOID DeviceObject)
1988 {
1989 UNIMPLEMENTED;
1990 return STATUS_NOT_IMPLEMENTED;
1991 }
1992
1993 /*
1994 * @implemented
1995 */
1996 PFILE_OBJECT
1997 NTAPI
1998 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
1999 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
2000 OUT PHANDLE FileObjectHandle OPTIONAL)
2001 {
2002 PFILE_OBJECT CreatedFileObject;
2003 NTSTATUS Status;
2004 HANDLE FileHandle;
2005 OBJECT_ATTRIBUTES ObjectAttributes;
2006 PAGED_CODE();
2007 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2008
2009 /* Choose Device Object */
2010 if (FileObject) DeviceObject = FileObject->DeviceObject;
2011
2012 /* Reference the device object and initialize attributes */
2013 InterlockedIncrement(&DeviceObject->ReferenceCount);
2014 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2015
2016 /* Create the File Object */
2017 Status = ObCreateObject(KernelMode,
2018 IoFileObjectType,
2019 &ObjectAttributes,
2020 KernelMode,
2021 NULL,
2022 sizeof(FILE_OBJECT),
2023 sizeof(FILE_OBJECT),
2024 0,
2025 (PVOID*)&CreatedFileObject);
2026 if (!NT_SUCCESS(Status))
2027 {
2028 /* Fail */
2029 IopDereferenceDeviceObject(DeviceObject, FALSE);
2030 ExRaiseStatus(Status);
2031 }
2032
2033 /* Set File Object Data */
2034 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2035 CreatedFileObject->DeviceObject = DeviceObject;
2036 CreatedFileObject->Type = IO_TYPE_FILE;
2037 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2038 CreatedFileObject->Flags = FO_STREAM_FILE;
2039
2040 /* Initialize the wait event */
2041 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2042
2043 /* Insert it to create a handle for it */
2044 Status = ObInsertObject(CreatedFileObject,
2045 NULL,
2046 FILE_READ_DATA,
2047 1,
2048 (PVOID*)&CreatedFileObject,
2049 &FileHandle);
2050 if (!NT_SUCCESS(Status)) ExRaiseStatus(Status);
2051
2052 /* Set the handle created flag */
2053 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2054 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2055
2056 /* Check if we have a VPB */
2057 if (DeviceObject->Vpb)
2058 {
2059 /* Reference it */
2060 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2061 }
2062
2063 /* Check if the caller wants the handle */
2064 if (FileObjectHandle)
2065 {
2066 /* Return it */
2067 *FileObjectHandle = FileHandle;
2068 ObDereferenceObject(CreatedFileObject);
2069 }
2070 else
2071 {
2072 /* Otherwise, close it */
2073 ObCloseHandle(FileHandle, KernelMode);
2074 }
2075
2076 /* Return the file object */
2077 return CreatedFileObject;
2078 }
2079
2080 /*
2081 * @implemented
2082 */
2083 PFILE_OBJECT
2084 NTAPI
2085 IoCreateStreamFileObject(IN PFILE_OBJECT FileObject,
2086 IN PDEVICE_OBJECT DeviceObject)
2087 {
2088 /* Call the newer function */
2089 return IoCreateStreamFileObjectEx(FileObject, DeviceObject, NULL);
2090 }
2091
2092 /*
2093 * @implemented
2094 */
2095 PFILE_OBJECT
2096 NTAPI
2097 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
2098 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
2099 {
2100 PFILE_OBJECT CreatedFileObject;
2101 NTSTATUS Status;
2102 OBJECT_ATTRIBUTES ObjectAttributes;
2103 PAGED_CODE();
2104 IOTRACE(IO_FILE_DEBUG, "FileObject: %p\n", FileObject);
2105
2106 /* Choose Device Object */
2107 if (FileObject) DeviceObject = FileObject->DeviceObject;
2108
2109 /* Reference the device object and initialize attributes */
2110 InterlockedIncrement(&DeviceObject->ReferenceCount);
2111 InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL);
2112
2113 /* Create the File Object */
2114 Status = ObCreateObject(KernelMode,
2115 IoFileObjectType,
2116 &ObjectAttributes,
2117 KernelMode,
2118 NULL,
2119 sizeof(FILE_OBJECT),
2120 sizeof(FILE_OBJECT),
2121 0,
2122 (PVOID*)&CreatedFileObject);
2123 if (!NT_SUCCESS(Status))
2124 {
2125 /* Fail */
2126 IopDereferenceDeviceObject(DeviceObject, FALSE);
2127 ExRaiseStatus(Status);
2128 }
2129
2130 /* Set File Object Data */
2131 RtlZeroMemory(CreatedFileObject, sizeof(FILE_OBJECT));
2132 CreatedFileObject->DeviceObject = DeviceObject;
2133 CreatedFileObject->Type = IO_TYPE_FILE;
2134 CreatedFileObject->Size = sizeof(FILE_OBJECT);
2135 CreatedFileObject->Flags = FO_STREAM_FILE;
2136
2137 /* Initialize the wait event */
2138 KeInitializeEvent(&CreatedFileObject->Event, SynchronizationEvent, FALSE);
2139
2140 /* Destroy create information */
2141 ObFreeObjectCreateInfoBuffer(OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->
2142 ObjectCreateInfo);
2143 OBJECT_TO_OBJECT_HEADER(CreatedFileObject)->ObjectCreateInfo = NULL;
2144
2145 /* Set the handle created flag */
2146 CreatedFileObject->Flags |= FO_HANDLE_CREATED;
2147 ASSERT(CreatedFileObject->Type == IO_TYPE_FILE);
2148
2149 /* Check if we have a VPB */
2150 if (DeviceObject->Vpb)
2151 {
2152 /* Reference it */
2153 InterlockedIncrement((PLONG)&DeviceObject->Vpb->ReferenceCount);
2154 }
2155
2156 /* Return the file object */
2157 return CreatedFileObject;
2158 }
2159
2160 /*
2161 * @implemented
2162 */
2163 PGENERIC_MAPPING
2164 NTAPI
2165 IoGetFileObjectGenericMapping(VOID)
2166 {
2167 /* Return the mapping */
2168 return &IopFileMapping;
2169 }
2170
2171 /*
2172 * @implemented
2173 */
2174 BOOLEAN
2175 NTAPI
2176 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
2177 {
2178 /* Return the flag status */
2179 return FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2180 }
2181
2182 /*
2183 * @implemented
2184 */
2185 BOOLEAN
2186 NTAPI
2187 IoFastQueryNetworkAttributes(IN POBJECT_ATTRIBUTES ObjectAttributes,
2188 IN ACCESS_MASK DesiredAccess,
2189 IN ULONG OpenOptions,
2190 OUT PIO_STATUS_BLOCK IoStatus,
2191 OUT PFILE_NETWORK_OPEN_INFORMATION Buffer)
2192 {
2193 NTSTATUS Status;
2194 DUMMY_FILE_OBJECT DummyFileObject;
2195 HANDLE Handle;
2196 OPEN_PACKET OpenPacket;
2197 PAGED_CODE();
2198 IOTRACE(IO_FILE_DEBUG, "FileName: %wZ\n", ObjectAttributes->ObjectName);
2199
2200 /* Setup the Open Packet */
2201 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
2202 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
2203 OpenPacket.Size = sizeof(OPEN_PACKET);
2204 OpenPacket.CreateOptions = OpenOptions | FILE_OPEN_REPARSE_POINT;
2205 OpenPacket.ShareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE;
2206 OpenPacket.Options = IO_FORCE_ACCESS_CHECK;
2207 OpenPacket.Disposition = FILE_OPEN;
2208 OpenPacket.NetworkInformation = Buffer;
2209 OpenPacket.QueryOnly = TRUE;
2210 OpenPacket.FullAttributes = TRUE;
2211 OpenPacket.DummyFileObject = &DummyFileObject;
2212
2213 /*
2214 * Attempt opening the file. This will call the I/O Parse Routine for
2215 * the File Object (IopParseDevice) which will use the dummy file obejct
2216 * send the IRP to its device object. Note that we have two statuses
2217 * to worry about: the Object Manager's status (in Status) and the I/O
2218 * status, which is in the Open Packet's Final Status, and determined
2219 * by the Parse Check member.
2220 */
2221 Status = ObOpenObjectByName(ObjectAttributes,
2222 NULL,
2223 KernelMode,
2224 NULL,
2225 DesiredAccess,
2226 &OpenPacket,
2227 &Handle);
2228 if (OpenPacket.ParseCheck != TRUE)
2229 {
2230 /* Parse failed */
2231 IoStatus->Status = Status;
2232 }
2233 else
2234 {
2235 /* Use the Io status */
2236 IoStatus->Status = OpenPacket.FinalStatus;
2237 IoStatus->Information = OpenPacket.Information;
2238 }
2239
2240 /* Return success */
2241 return TRUE;
2242 }
2243
2244 /*
2245 * @implemented
2246 */
2247 VOID
2248 NTAPI
2249 IoUpdateShareAccess(IN PFILE_OBJECT FileObject,
2250 OUT PSHARE_ACCESS ShareAccess)
2251 {
2252 PAGED_CODE();
2253
2254 /* Check if the file has an extension */
2255 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2256 {
2257 /* Check if caller specified to ignore access checks */
2258 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2259 {
2260 /* Don't update share access */
2261 return;
2262 }
2263 }
2264
2265 /* Otherwise, check if there's any access present */
2266 if ((FileObject->ReadAccess) ||
2267 (FileObject->WriteAccess) ||
2268 (FileObject->DeleteAccess))
2269 {
2270 /* Increase the open count */
2271 ShareAccess->OpenCount++;
2272
2273 /* Add new share access */
2274 ShareAccess->Readers += FileObject->ReadAccess;
2275 ShareAccess->Writers += FileObject->WriteAccess;
2276 ShareAccess->Deleters += FileObject->DeleteAccess;
2277 ShareAccess->SharedRead += FileObject->SharedRead;
2278 ShareAccess->SharedWrite += FileObject->SharedWrite;
2279 ShareAccess->SharedDelete += FileObject->SharedDelete;
2280 }
2281 }
2282
2283 /*
2284 * @implemented
2285 */
2286 NTSTATUS
2287 NTAPI
2288 IoCheckShareAccess(IN ACCESS_MASK DesiredAccess,
2289 IN ULONG DesiredShareAccess,
2290 IN PFILE_OBJECT FileObject,
2291 IN PSHARE_ACCESS ShareAccess,
2292 IN BOOLEAN Update)
2293 {
2294 BOOLEAN ReadAccess;
2295 BOOLEAN WriteAccess;
2296 BOOLEAN DeleteAccess;
2297 BOOLEAN SharedRead;
2298 BOOLEAN SharedWrite;
2299 BOOLEAN SharedDelete;
2300 PAGED_CODE();
2301
2302 /* Get access masks */
2303 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
2304 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
2305 DeleteAccess = (DesiredAccess & DELETE) != 0;
2306
2307 /* Set them in the file object */
2308 FileObject->ReadAccess = ReadAccess;
2309 FileObject->WriteAccess = WriteAccess;
2310 FileObject->DeleteAccess = DeleteAccess;
2311
2312 /* Check if the file has an extension */
2313 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2314 {
2315 /* Check if caller specified to ignore access checks */
2316 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2317 {
2318 /* Don't check share access */
2319 return STATUS_SUCCESS;
2320 }
2321 }
2322
2323 /* Check if we have any access */
2324 if ((ReadAccess) || (WriteAccess) || (DeleteAccess))
2325 {
2326 /* Get shared access masks */
2327 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
2328 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
2329 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
2330
2331 /* Set them */
2332 FileObject->SharedRead = SharedRead;
2333 FileObject->SharedWrite = SharedWrite;
2334 FileObject->SharedDelete = SharedDelete;
2335
2336 /* Check if the shared access is violated */
2337 if ((ReadAccess &&
2338 (ShareAccess->SharedRead < ShareAccess->OpenCount)) ||
2339 (WriteAccess &&
2340 (ShareAccess->SharedWrite < ShareAccess->OpenCount)) ||
2341 (DeleteAccess &&
2342 (ShareAccess->SharedDelete < ShareAccess->OpenCount)) ||
2343 ((ShareAccess->Readers != 0) && !SharedRead) ||
2344 ((ShareAccess->Writers != 0) && !SharedWrite) ||
2345 ((ShareAccess->Deleters != 0) && !SharedDelete))
2346 {
2347 /* Sharing violation, fail */
2348 return STATUS_SHARING_VIOLATION;
2349 }
2350
2351 /* It's not, check if caller wants us to update it */
2352 if (Update)
2353 {
2354 /* Increase open count */
2355 ShareAccess->OpenCount++;
2356
2357 /* Update shared access */
2358 ShareAccess->Readers += ReadAccess;
2359 ShareAccess->Writers += WriteAccess;
2360 ShareAccess->Deleters += DeleteAccess;
2361 ShareAccess->SharedRead += SharedRead;
2362 ShareAccess->SharedWrite += SharedWrite;
2363 ShareAccess->SharedDelete += SharedDelete;
2364 }
2365 }
2366
2367 /* Validation successful */
2368 return STATUS_SUCCESS;
2369 }
2370
2371 /*
2372 * @implemented
2373 */
2374 VOID
2375 NTAPI
2376 IoRemoveShareAccess(IN PFILE_OBJECT FileObject,
2377 IN PSHARE_ACCESS ShareAccess)
2378 {
2379 PAGED_CODE();
2380
2381 /* Check if the file has an extension */
2382 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2383 {
2384 /* Check if caller specified to ignore access checks */
2385 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2386 {
2387 /* Don't update share access */
2388 return;
2389 }
2390 }
2391
2392 /* Otherwise, check if there's any access present */
2393 if ((FileObject->ReadAccess) ||
2394 (FileObject->WriteAccess) ||
2395 (FileObject->DeleteAccess))
2396 {
2397 /* Decrement the open count */
2398 ShareAccess->OpenCount--;
2399
2400 /* Remove share access */
2401 ShareAccess->Readers -= FileObject->ReadAccess;
2402 ShareAccess->Writers -= FileObject->WriteAccess;
2403 ShareAccess->Deleters -= FileObject->DeleteAccess;
2404 ShareAccess->SharedRead -= FileObject->SharedRead;
2405 ShareAccess->SharedWrite -= FileObject->SharedWrite;
2406 ShareAccess->SharedDelete -= FileObject->SharedDelete;
2407 }
2408 }
2409
2410 /*
2411 * @implemented
2412 */
2413 VOID
2414 NTAPI
2415 IoSetShareAccess(IN ACCESS_MASK DesiredAccess,
2416 IN ULONG DesiredShareAccess,
2417 IN PFILE_OBJECT FileObject,
2418 OUT PSHARE_ACCESS ShareAccess)
2419 {
2420 BOOLEAN ReadAccess;
2421 BOOLEAN WriteAccess;
2422 BOOLEAN DeleteAccess;
2423 BOOLEAN SharedRead;
2424 BOOLEAN SharedWrite;
2425 BOOLEAN SharedDelete;
2426 BOOLEAN Update = TRUE;
2427 PAGED_CODE();
2428
2429 ReadAccess = (DesiredAccess & (FILE_READ_DATA | FILE_EXECUTE)) != 0;
2430 WriteAccess = (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0;
2431 DeleteAccess = (DesiredAccess & DELETE) != 0;
2432
2433 /* Check if the file has an extension */
2434 if (FileObject->Flags & FO_FILE_OBJECT_HAS_EXTENSION)
2435 {
2436 /* Check if caller specified to ignore access checks */
2437 //if (FileObject->FoExtFlags & IO_IGNORE_SHARE_ACCESS_CHECK)
2438 {
2439 /* Don't update share access */
2440 Update = FALSE;
2441 }
2442 }
2443
2444 /* Update basic access */
2445 FileObject->ReadAccess = ReadAccess;
2446 FileObject->WriteAccess = WriteAccess;
2447 FileObject->DeleteAccess = DeleteAccess;
2448
2449 /* Check if we have no access as all */
2450 if (!(ReadAccess) && !(WriteAccess) && !(DeleteAccess))
2451 {
2452 /* Check if we need to update the structure */
2453 if (!Update) return;
2454
2455 /* Otherwise, clear data */
2456 ShareAccess->OpenCount = 0;
2457 ShareAccess->Readers = 0;
2458 ShareAccess->Writers = 0;
2459 ShareAccess->Deleters = 0;
2460 ShareAccess->SharedRead = 0;
2461 ShareAccess->SharedWrite = 0;
2462 ShareAccess->SharedDelete = 0;
2463 }
2464 else
2465 {
2466 /* Calculate shared access */
2467 SharedRead = (DesiredShareAccess & FILE_SHARE_READ) != 0;
2468 SharedWrite = (DesiredShareAccess & FILE_SHARE_WRITE) != 0;
2469 SharedDelete = (DesiredShareAccess & FILE_SHARE_DELETE) != 0;
2470
2471 /* Set it in the FO */
2472 FileObject->SharedRead = SharedRead;
2473 FileObject->SharedWrite = SharedWrite;
2474 FileObject->SharedDelete = SharedDelete;
2475
2476 /* Check if we need to update the structure */
2477 if (!Update) return;
2478
2479 /* Otherwise, set data */
2480 ShareAccess->OpenCount = 1;
2481 ShareAccess->Readers = ReadAccess;
2482 ShareAccess->Writers = WriteAccess;
2483 ShareAccess->Deleters = DeleteAccess;
2484 ShareAccess->SharedRead = SharedRead;
2485 ShareAccess->SharedWrite = SharedWrite;
2486 ShareAccess->SharedDelete = SharedDelete;
2487 }
2488 }
2489
2490 /*
2491 * @implemented
2492 */
2493 VOID
2494 NTAPI
2495 IoCancelFileOpen(IN PDEVICE_OBJECT DeviceObject,
2496 IN PFILE_OBJECT FileObject)
2497 {
2498 PIRP Irp;
2499 KEVENT Event;
2500 KIRQL OldIrql;
2501 NTSTATUS Status;
2502 PIO_STACK_LOCATION Stack;
2503
2504 /* Check if handles were already created for the
2505 * open file. If so, that's over.
2506 */
2507 if (FileObject->Flags & FO_HANDLE_CREATED)
2508 KeBugCheckEx(INVALID_CANCEL_OF_FILE_OPEN,
2509 (ULONG_PTR)FileObject,
2510 (ULONG_PTR)DeviceObject, 0, 0);
2511
2512 /* Reset the events */
2513 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2514 KeClearEvent(&FileObject->Event);
2515
2516 /* Allocate the IRP we'll use */
2517 Irp = IopAllocateIrpMustSucceed(DeviceObject->StackSize);
2518 /* Properly set it */
2519 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2520 Irp->UserEvent = &Event;
2521 Irp->UserIosb = &Irp->IoStatus;
2522 Irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
2523 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2524 Irp->RequestorMode = KernelMode;
2525 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
2526
2527 Stack = IoGetNextIrpStackLocation(Irp);
2528 Stack->MajorFunction = IRP_MJ_CLEANUP;
2529 Stack->FileObject = FileObject;
2530
2531 /* Put on top of IRPs list of the thread */
2532 IopQueueIrpToThread(Irp);
2533
2534 /* Call the driver */
2535 Status = IoCallDriver(DeviceObject, Irp);
2536 if (Status == STATUS_PENDING)
2537 {
2538 KeWaitForSingleObject(&Event, UserRequest,
2539 KernelMode, FALSE, NULL);
2540 }
2541
2542 /* Remove from IRPs list */
2543 KeRaiseIrql(APC_LEVEL, &OldIrql);
2544 IopUnQueueIrpFromThread(Irp);
2545 KeLowerIrql(OldIrql);
2546
2547 /* Free the IRP */
2548 IoFreeIrp(Irp);
2549
2550 /* Clear the event */
2551 KeClearEvent(&FileObject->Event);
2552 /* And finally, mark the open operation as canceled */
2553 FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
2554 }
2555
2556 /*
2557 * @unimplemented
2558 */
2559 NTSTATUS
2560 NTAPI
2561 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
2562 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
2563 {
2564 UNIMPLEMENTED;
2565 return STATUS_NOT_IMPLEMENTED;
2566 }
2567
2568 /*
2569 * @implemented
2570 */
2571 NTSTATUS
2572 NTAPI
2573 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
2574 IN BOOLEAN Remote)
2575 {
2576 NTSTATUS Status = STATUS_SUCCESS;
2577 BOOLEAN FlagSet;
2578
2579 /* Get the flag status */
2580 FlagSet = FileObject->Flags & FO_REMOTE_ORIGIN ? TRUE : FALSE;
2581
2582 /* Don't set the flag if it was set already, and don't remove it if it wasn't set */
2583 if (Remote && !FlagSet)
2584 {
2585 /* Set the flag */
2586 FileObject->Flags |= FO_REMOTE_ORIGIN;
2587 }
2588 else if (!Remote && FlagSet)
2589 {
2590 /* Remove the flag */
2591 FileObject->Flags &= ~FO_REMOTE_ORIGIN;
2592 }
2593 else
2594 {
2595 /* Fail */
2596 Status = STATUS_INVALID_PARAMETER_MIX;
2597 }
2598
2599 /* Return status */
2600 return Status;
2601 }
2602
2603 /*
2604 * @implemented
2605 */
2606 NTSTATUS
2607 NTAPI
2608 NtCreateFile(PHANDLE FileHandle,
2609 ACCESS_MASK DesiredAccess,
2610 POBJECT_ATTRIBUTES ObjectAttributes,
2611 PIO_STATUS_BLOCK IoStatusBlock,
2612 PLARGE_INTEGER AllocateSize,
2613 ULONG FileAttributes,
2614 ULONG ShareAccess,
2615 ULONG CreateDisposition,
2616 ULONG CreateOptions,
2617 PVOID EaBuffer,
2618 ULONG EaLength)
2619 {
2620 /* Call the I/O Function */
2621 return IoCreateFile(FileHandle,
2622 DesiredAccess,
2623 ObjectAttributes,
2624 IoStatusBlock,
2625 AllocateSize,
2626 FileAttributes,
2627 ShareAccess,
2628 CreateDisposition,
2629 CreateOptions,
2630 EaBuffer,
2631 EaLength,
2632 CreateFileTypeNone,
2633 NULL,
2634 0);
2635 }
2636
2637 NTSTATUS
2638 NTAPI
2639 NtCreateMailslotFile(OUT PHANDLE FileHandle,
2640 IN ACCESS_MASK DesiredAccess,
2641 IN POBJECT_ATTRIBUTES ObjectAttributes,
2642 OUT PIO_STATUS_BLOCK IoStatusBlock,
2643 IN ULONG CreateOptions,
2644 IN ULONG MailslotQuota,
2645 IN ULONG MaxMessageSize,
2646 IN PLARGE_INTEGER TimeOut)
2647 {
2648 MAILSLOT_CREATE_PARAMETERS Buffer;
2649 PAGED_CODE();
2650
2651 /* Check for Timeout */
2652 if (TimeOut)
2653 {
2654 /* check if the call came from user mode */
2655 if (KeGetPreviousMode() != KernelMode)
2656 {
2657 /* Enter SEH for Probe */
2658 _SEH2_TRY
2659 {
2660 /* Probe the timeout */
2661 Buffer.ReadTimeout = ProbeForReadLargeInteger(TimeOut);
2662 }
2663 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2664 {
2665 /* Return the exception code */
2666 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2667 }
2668 _SEH2_END;
2669 }
2670 else
2671 {
2672 /* Otherwise, capture directly */
2673 Buffer.ReadTimeout = *TimeOut;
2674 }
2675
2676 /* Set the correct setting */
2677 Buffer.TimeoutSpecified = TRUE;
2678 }
2679 else
2680 {
2681 /* Tell the FSD we don't have a timeout */
2682 Buffer.TimeoutSpecified = FALSE;
2683 }
2684
2685 /* Set Settings */
2686 Buffer.MailslotQuota = MailslotQuota;
2687 Buffer.MaximumMessageSize = MaxMessageSize;
2688
2689 /* Call I/O */
2690 return IoCreateFile(FileHandle,
2691 DesiredAccess,
2692 ObjectAttributes,
2693 IoStatusBlock,
2694 NULL,
2695 0,
2696 FILE_SHARE_READ | FILE_SHARE_WRITE,
2697 FILE_CREATE,
2698 CreateOptions,
2699 NULL,
2700 0,
2701 CreateFileTypeMailslot,
2702 (PVOID)&Buffer,
2703 0);
2704 }
2705
2706 NTSTATUS
2707 NTAPI
2708 NtCreateNamedPipeFile(OUT PHANDLE FileHandle,
2709 IN ACCESS_MASK DesiredAccess,
2710 IN POBJECT_ATTRIBUTES ObjectAttributes,
2711 OUT PIO_STATUS_BLOCK IoStatusBlock,
2712 IN ULONG ShareAccess,
2713 IN ULONG CreateDisposition,
2714 IN ULONG CreateOptions,
2715 IN ULONG NamedPipeType,
2716 IN ULONG ReadMode,
2717 IN ULONG CompletionMode,
2718 IN ULONG MaximumInstances,
2719 IN ULONG InboundQuota,
2720 IN ULONG OutboundQuota,
2721 IN PLARGE_INTEGER DefaultTimeout)
2722 {
2723 NAMED_PIPE_CREATE_PARAMETERS Buffer;
2724 PAGED_CODE();
2725
2726 /* Check for Timeout */
2727 if (DefaultTimeout)
2728 {
2729 /* check if the call came from user mode */
2730 if (KeGetPreviousMode() != KernelMode)
2731 {
2732 /* Enter SEH for Probe */
2733 _SEH2_TRY
2734 {
2735 /* Probe the timeout */
2736 Buffer.DefaultTimeout =
2737 ProbeForReadLargeInteger(DefaultTimeout);
2738 }
2739 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2740 {
2741 /* Return the exception code */
2742 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2743 }
2744 _SEH2_END;
2745 }
2746 else
2747 {
2748 /* Otherwise, capture directly */
2749 Buffer.DefaultTimeout = *DefaultTimeout;
2750 }
2751
2752 /* Set the correct setting */
2753 Buffer.TimeoutSpecified = TRUE;
2754 }
2755 else
2756 {
2757 /* Tell the FSD we don't have a timeout */
2758 Buffer.TimeoutSpecified = FALSE;
2759 }
2760
2761 /* Set Settings */
2762 Buffer.NamedPipeType = NamedPipeType;
2763 Buffer.ReadMode = ReadMode;
2764 Buffer.CompletionMode = CompletionMode;
2765 Buffer.MaximumInstances = MaximumInstances;
2766 Buffer.InboundQuota = InboundQuota;
2767 Buffer.OutboundQuota = OutboundQuota;
2768
2769 /* Call I/O */
2770 return IoCreateFile(FileHandle,
2771 DesiredAccess,
2772 ObjectAttributes,
2773 IoStatusBlock,
2774 NULL,
2775 0,
2776 ShareAccess,
2777 CreateDisposition,
2778 CreateOptions,
2779 NULL,
2780 0,
2781 CreateFileTypeNamedPipe,
2782 (PVOID)&Buffer,
2783 0);
2784 }
2785
2786 NTSTATUS
2787 NTAPI
2788 NtFlushWriteBuffer(VOID)
2789 {
2790 PAGED_CODE();
2791
2792 /* Call the kernel */
2793 KeFlushWriteBuffer();
2794 return STATUS_SUCCESS;
2795 }
2796
2797 /*
2798 * @implemented
2799 */
2800 NTSTATUS
2801 NTAPI
2802 NtOpenFile(OUT PHANDLE FileHandle,
2803 IN ACCESS_MASK DesiredAccess,
2804 IN POBJECT_ATTRIBUTES ObjectAttributes,
2805 OUT PIO_STATUS_BLOCK IoStatusBlock,
2806 IN ULONG ShareAccess,
2807 IN ULONG OpenOptions)
2808 {
2809 /* Call the I/O Function */
2810 return IoCreateFile(FileHandle,
2811 DesiredAccess,
2812 ObjectAttributes,
2813 IoStatusBlock,
2814 NULL,
2815 0,
2816 ShareAccess,
2817 FILE_OPEN,
2818 OpenOptions,
2819 NULL,
2820 0,
2821 CreateFileTypeNone,
2822 NULL,
2823 0);
2824 }
2825
2826 NTSTATUS
2827 NTAPI
2828 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2829 OUT PFILE_BASIC_INFORMATION FileInformation)
2830 {
2831 /* Call the internal helper API */
2832 return IopQueryAttributesFile(ObjectAttributes,
2833 FileBasicInformation,
2834 sizeof(FILE_BASIC_INFORMATION),
2835 FileInformation);
2836 }
2837
2838 NTSTATUS
2839 NTAPI
2840 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2841 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
2842 {
2843 /* Call the internal helper API */
2844 return IopQueryAttributesFile(ObjectAttributes,
2845 FileNetworkOpenInformation,
2846 sizeof(FILE_NETWORK_OPEN_INFORMATION),
2847 FileInformation);
2848 }
2849
2850 /**
2851 * @name NtCancelIoFile
2852 *
2853 * Cancel all pending I/O operations in the current thread for specified
2854 * file object.
2855 *
2856 * @param FileHandle
2857 * Handle to file object to cancel requests for. No specific
2858 * access rights are needed.
2859 * @param IoStatusBlock
2860 * Pointer to status block which is filled with final completition
2861 * status on successful return.
2862 *
2863 * @return Status.
2864 *
2865 * @implemented
2866 */
2867 NTSTATUS
2868 NTAPI
2869 NtCancelIoFile(IN HANDLE FileHandle,
2870 OUT PIO_STATUS_BLOCK IoStatusBlock)
2871 {
2872 PFILE_OBJECT FileObject;
2873 PETHREAD Thread;
2874 PIRP Irp;
2875 KIRQL OldIrql;
2876 BOOLEAN OurIrpsInList = FALSE;
2877 LARGE_INTEGER Interval;
2878 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
2879 NTSTATUS Status;
2880 PLIST_ENTRY ListHead, NextEntry;
2881 PAGED_CODE();
2882 IOTRACE(IO_API_DEBUG, "FileHandle: %p\n", FileHandle);
2883
2884 /* Check the previous mode */
2885 if (PreviousMode != KernelMode)
2886 {
2887 /* Enter SEH for probing */
2888 _SEH2_TRY
2889 {
2890 /* Probe the I/O Status Block */
2891 ProbeForWriteIoStatusBlock(IoStatusBlock);
2892 }
2893 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2894 {
2895 /* Return the exception code */
2896 _SEH2_YIELD(return _SEH2_GetExceptionCode());
2897 }
2898 _SEH2_END;
2899 }
2900
2901 /* Reference the file object */
2902 Status = ObReferenceObjectByHandle(FileHandle,
2903 0,
2904 IoFileObjectType,
2905 PreviousMode,
2906 (PVOID*)&FileObject,
2907 NULL);
2908 if (!NT_SUCCESS(Status)) return Status;
2909
2910 /* IRP cancellations are synchronized at APC_LEVEL. */
2911 KeRaiseIrql(APC_LEVEL, &OldIrql);
2912
2913 /* Get the current thread */
2914 Thread = PsGetCurrentThread();
2915
2916 /* Update the operation counts */
2917 IopUpdateOperationCount(IopOtherTransfer);
2918
2919 /* Loop the list */
2920 ListHead = &Thread->IrpList;
2921 NextEntry = ListHead->Flink;
2922 while (ListHead != NextEntry)
2923 {
2924 /* Get the IRP and check if the File Object matches */
2925 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
2926 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
2927 {
2928 /* Cancel this IRP and keep looping */
2929 IoCancelIrp(Irp);
2930 OurIrpsInList = TRUE;
2931 }
2932
2933 /* Go to the next entry */
2934 NextEntry = NextEntry->Flink;
2935 }
2936
2937 /* Lower the IRQL */
2938 KeLowerIrql(OldIrql);
2939
2940 /* Check if we had found an IRP */
2941 if (OurIrpsInList)
2942 {
2943 /* Setup a 10ms wait */
2944 Interval.QuadPart = -100000;
2945
2946 /* Start looping */
2947 while (OurIrpsInList)
2948 {
2949 /* Do the wait */
2950 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
2951 OurIrpsInList = FALSE;
2952
2953 /* Raise IRQL */
2954 KeRaiseIrql(APC_LEVEL, &OldIrql);
2955
2956 /* Now loop the list again */
2957 NextEntry = ListHead->Flink;
2958 while (NextEntry != ListHead)
2959 {
2960 /* Get the IRP and check if the File Object matches */
2961 Irp = CONTAINING_RECORD(NextEntry, IRP, ThreadListEntry);
2962 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
2963 {
2964 /* Keep looping */
2965 OurIrpsInList = TRUE;
2966 break;
2967 }
2968
2969 /* Go to the next entry */
2970 NextEntry = NextEntry->Flink;
2971 }
2972
2973 /* Lower the IRQL */
2974 KeLowerIrql(OldIrql);
2975 }
2976 }
2977
2978 /* Enter SEH for writing back the I/O Status */
2979 _SEH2_TRY
2980 {
2981 /* Write success */
2982 IoStatusBlock->Status = STATUS_SUCCESS;
2983 IoStatusBlock->Information = 0;
2984 }
2985 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2986 {
2987 /* Ignore exception */
2988 }
2989 _SEH2_END;
2990
2991 /* Dereference the file object and return success */
2992 ObDereferenceObject(FileObject);
2993 return STATUS_SUCCESS;
2994 }
2995
2996 /*
2997 * @implemented
2998 */
2999 NTSTATUS
3000 NTAPI
3001 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
3002 {
3003 NTSTATUS Status;
3004 DUMMY_FILE_OBJECT DummyFileObject;
3005 HANDLE Handle;
3006 KPROCESSOR_MODE AccessMode = KeGetPreviousMode();
3007 OPEN_PACKET OpenPacket;
3008 PAGED_CODE();
3009 IOTRACE(IO_API_DEBUG, "FileMame: %wZ\n", ObjectAttributes->ObjectName);
3010
3011 /* Setup the Open Packet */
3012 RtlZeroMemory(&OpenPacket, sizeof(OPEN_PACKET));
3013 OpenPacket.Type = IO_TYPE_OPEN_PACKET;
3014 OpenPacket.Size = sizeof(OPEN_PACKET);
3015 OpenPacket.CreateOptions = FILE_DELETE_ON_CLOSE;
3016 OpenPacket.ShareAccess = FILE_SHARE_READ |
3017 FILE_SHARE_WRITE |
3018 FILE_SHARE_DELETE;
3019 OpenPacket.Disposition = FILE_OPEN;
3020 OpenPacket.DeleteOnly = TRUE;
3021 OpenPacket.DummyFileObject = &DummyFileObject;
3022
3023 /* Update the operation counts */
3024 IopUpdateOperationCount(IopOtherTransfer);
3025
3026 /*
3027 * Attempt opening the file. This will call the I/O Parse Routine for
3028 * the File Object (IopParseDevice) which will use the dummy file obejct
3029 * send the IRP to its device object. Note that we have two statuses
3030 * to worry about: the Object Manager's status (in Status) and the I/O
3031 * status, which is in the Open Packet's Final Status, and determined
3032 * by the Parse Check member.
3033 */
3034 Status = ObOpenObjectByName(ObjectAttributes,
3035 NULL,
3036 AccessMode,
3037 NULL,
3038 DELETE,
3039 &OpenPacket,
3040 &Handle);
3041 if (OpenPacket.ParseCheck != TRUE) return Status;
3042
3043 /* Retrn the Io status */
3044 return OpenPacket.FinalStatus;
3045 }
3046
3047 /* EOF */