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