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