Reuse buffer in IopQueryNameFile, since it's temporary and the first one we allocate...
[reactos.git] / reactos / ntoskrnl / io / file.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/file.c
5 * PURPOSE: I/O File Object & NT File Handle Access/Managment of Files.
6 *
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 * David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 /* GLOBALS *******************************************************************/
18
19 #define TAG_SYSB TAG('S', 'Y', 'S', 'B')
20 #define TAG_LOCK TAG('F','l','c','k')
21 #define TAG_FILE_NAME TAG('F', 'N', 'A', 'M')
22
23 extern GENERIC_MAPPING IopFileMapping;
24
25 NTSTATUS
26 STDCALL
27 SeSetWorldSecurityDescriptor(SECURITY_INFORMATION SecurityInformation,
28 PSECURITY_DESCRIPTOR SecurityDescriptor,
29 PULONG BufferLength);
30
31 /* INTERNAL FUNCTIONS ********************************************************/
32
33 static
34 NTSTATUS
35 STDCALL
36 IopLockFileCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
37 IN PIRP Irp,
38 IN PVOID Context)
39 {
40 ExFreePool(Context);
41 return STATUS_SUCCESS;
42 // FIXME: Should I call IoFreeIrp and return STATUS_MORE_PROCESSING_REQUIRED?
43 }
44
45 /*
46 * NAME INTERNAL
47 * IopCreateFile
48 *
49 * DESCRIPTION
50 *
51 * ARGUMENTS
52 *
53 * RETURN VALUE
54 *
55 * REVISIONS
56 */
57 NTSTATUS
58 STDCALL
59 IopCreateFile(PVOID ObjectBody,
60 PVOID Parent,
61 PWSTR RemainingPath,
62 POBJECT_ATTRIBUTES ObjectAttributes)
63 {
64 PDEVICE_OBJECT DeviceObject;
65 PFILE_OBJECT FileObject = (PFILE_OBJECT) ObjectBody;
66 POBJECT_TYPE ParentObjectType;
67 NTSTATUS Status;
68
69 DPRINT("IopCreateFile(ObjectBody %x, Parent %x, RemainingPath %S)\n",
70 ObjectBody,
71 Parent,
72 RemainingPath);
73
74 if (NULL == Parent)
75 {
76 /* This is probably an attempt to create a meta fileobject (eg. for FAT)
77 for the cache manager, so return STATUS_SUCCESS */
78 DPRINT("Parent object was NULL\n");
79 return(STATUS_SUCCESS);
80 }
81
82 ParentObjectType = BODY_TO_HEADER(Parent)->ObjectType;
83
84 if (ParentObjectType != IoDeviceObjectType &&
85 ParentObjectType != IoFileObjectType)
86 {
87 DPRINT("Parent [%wZ] is a %S which is neither a file type nor a device type ; remaining path = %S\n",
88 &BODY_TO_HEADER(Parent)->Name,
89 BODY_TO_HEADER(Parent)->ObjectType->TypeName.Buffer,
90 RemainingPath);
91 return(STATUS_UNSUCCESSFUL);
92 }
93
94 Status = ObReferenceObjectByPointer(Parent,
95 STANDARD_RIGHTS_REQUIRED,
96 ParentObjectType,
97 UserMode);
98 if (!NT_SUCCESS(Status))
99 {
100 CPRINT("Failed to reference parent object %x\n", Parent);
101 return(Status);
102 }
103
104 if (ParentObjectType == IoDeviceObjectType)
105 {
106 /* Parent is a devce object */
107 DeviceObject = IoGetAttachedDevice((PDEVICE_OBJECT)Parent);
108 DPRINT("DeviceObject %x\n", DeviceObject);
109
110 if (RemainingPath == NULL)
111 {
112 FileObject->Flags = FileObject->Flags | FO_DIRECT_DEVICE_OPEN;
113 FileObject->FileName.Buffer = 0;
114 FileObject->FileName.Length = FileObject->FileName.MaximumLength = 0;
115 }
116 else
117 {
118 if ((DeviceObject->DeviceType != FILE_DEVICE_FILE_SYSTEM)
119 && (DeviceObject->DeviceType != FILE_DEVICE_DISK)
120 && (DeviceObject->DeviceType != FILE_DEVICE_CD_ROM)
121 && (DeviceObject->DeviceType != FILE_DEVICE_TAPE)
122 && (DeviceObject->DeviceType != FILE_DEVICE_NETWORK)
123 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
124 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
125 {
126 CPRINT("Device was wrong type\n");
127 return(STATUS_UNSUCCESSFUL);
128 }
129
130 if (DeviceObject->DeviceType != FILE_DEVICE_NETWORK
131 && (DeviceObject->DeviceType != FILE_DEVICE_NAMED_PIPE)
132 && (DeviceObject->DeviceType != FILE_DEVICE_MAILSLOT))
133 {
134 if (!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
135 {
136 DPRINT("Mount the logical volume\n");
137 Status = IoMountVolume(DeviceObject, FALSE);
138 DPRINT("Status %x\n", Status);
139 if (!NT_SUCCESS(Status))
140 {
141 CPRINT("Failed to mount logical volume (Status %x)\n",
142 Status);
143 return(Status);
144 }
145 }
146 DeviceObject = DeviceObject->Vpb->DeviceObject;
147 DPRINT("FsDeviceObject %lx\n", DeviceObject);
148 }
149 RtlpCreateUnicodeString(&(FileObject->FileName),
150 RemainingPath, NonPagedPool);
151 }
152 }
153 else
154 {
155 /* Parent is a file object */
156 if (RemainingPath == NULL)
157 {
158 CPRINT("Device is unnamed\n");
159 return STATUS_UNSUCCESSFUL;
160 }
161
162 DeviceObject = ((PFILE_OBJECT)Parent)->DeviceObject;
163 DPRINT("DeviceObject %x\n", DeviceObject);
164
165 FileObject->RelatedFileObject = (PFILE_OBJECT)Parent;
166
167 RtlpCreateUnicodeString(&(FileObject->FileName),
168 RemainingPath, NonPagedPool);
169 }
170
171 DPRINT("FileObject->FileName %wZ\n",
172 &FileObject->FileName);
173 FileObject->DeviceObject = DeviceObject;
174 DPRINT("FileObject %x DeviceObject %x\n",
175 FileObject,
176 DeviceObject);
177 FileObject->Vpb = DeviceObject->Vpb;
178 FileObject->Type = IO_TYPE_FILE;
179
180 return(STATUS_SUCCESS);
181 }
182
183 VOID
184 STDCALL
185 IopDeleteFile(PVOID ObjectBody)
186 {
187 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
188 PIRP Irp;
189 PIO_STACK_LOCATION StackPtr;
190 NTSTATUS Status;
191 KEVENT Event;
192 PDEVICE_OBJECT DeviceObject;
193
194 DPRINT("IopDeleteFile()\n");
195
196 if (FileObject->DeviceObject)
197 {
198 /* Check if this is a direct open or not */
199 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
200 {
201 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
202 }
203 else
204 {
205 DeviceObject = IoGetRelatedDeviceObject(FileObject);
206 }
207
208 /* Clear and set up Events */
209 KeClearEvent(&FileObject->Event);
210 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
211
212 /* Allocate an IRP */
213 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
214
215 /* Set it up */
216 Irp->UserEvent = &Event;
217 Irp->UserIosb = &Irp->IoStatus;
218 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
219 Irp->Tail.Overlay.OriginalFileObject = FileObject;
220 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
221
222 /* Set up Stack Pointer Data */
223 StackPtr = IoGetNextIrpStackLocation(Irp);
224 StackPtr->MajorFunction = IRP_MJ_CLOSE;
225 StackPtr->DeviceObject = DeviceObject;
226 StackPtr->FileObject = FileObject;
227
228 /* Call the FS Driver */
229 Status = IoCallDriver(DeviceObject, Irp);
230
231 /* Wait for completion */
232 if (Status == STATUS_PENDING)
233 {
234 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
235 }
236 IoFreeIrp(Irp);
237
238 }
239
240 /* Clear the file name */
241 if (FileObject->FileName.Buffer)
242 {
243 ExFreePool(FileObject->FileName.Buffer);
244 FileObject->FileName.Buffer = NULL;
245 }
246
247 /* Free the completion context */
248 if (FileObject->CompletionContext)
249 {
250 ObDereferenceObject(FileObject->CompletionContext->Port);
251 ExFreePool(FileObject->CompletionContext);
252 }
253 }
254
255 NTSTATUS
256 STDCALL
257 IopSecurityFile(PVOID ObjectBody,
258 SECURITY_OPERATION_CODE OperationCode,
259 SECURITY_INFORMATION SecurityInformation,
260 PSECURITY_DESCRIPTOR SecurityDescriptor,
261 PULONG BufferLength)
262 {
263 IO_STATUS_BLOCK IoStatusBlock;
264 PIO_STACK_LOCATION StackPtr;
265 PFILE_OBJECT FileObject;
266 PDEVICE_OBJECT DeviceObject;
267 ULONG MajorFunction;
268 PIRP Irp;
269 BOOLEAN LocalEvent = FALSE;
270 KEVENT Event;
271 NTSTATUS Status = STATUS_SUCCESS;
272
273 DPRINT("IopSecurityFile() called\n");
274
275 FileObject = (PFILE_OBJECT)ObjectBody;
276
277 if (OperationCode == QuerySecurityDescriptor)
278 {
279 MajorFunction = IRP_MJ_QUERY_SECURITY;
280 DPRINT("Query security descriptor\n");
281 }
282 else if (OperationCode == DeleteSecurityDescriptor)
283 {
284 DPRINT("Delete\n");
285 return STATUS_SUCCESS;
286 }
287 else if (OperationCode == AssignSecurityDescriptor)
288 {
289 /* If this is a direct open, we can assign it */
290 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
291 {
292 /* Get the Device Object */
293 DPRINT1("here\n");
294 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
295
296 /* Assign the Security Descriptor */
297 DeviceObject->SecurityDescriptor = SecurityDescriptor;
298 }
299 return STATUS_SUCCESS;
300 }
301 else
302 {
303 MajorFunction = IRP_MJ_SET_SECURITY;
304 DPRINT("Set security descriptor\n");
305
306 /* If this is a direct open, we can set it */
307 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
308 {
309 DPRINT1("Set SD unimplemented for Devices\n");
310 return STATUS_SUCCESS;
311 }
312 }
313
314 /* Get the Device Object */
315 DPRINT1("FileObject: %p\n", FileObject);
316 DeviceObject = IoGetRelatedDeviceObject(FileObject);
317
318 /* Check if we should use Sync IO or not */
319 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
320 {
321 /* Use File Object event */
322 KeClearEvent(&FileObject->Event);
323 }
324 else
325 {
326 /* Use local event */
327 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
328 LocalEvent = TRUE;
329 }
330
331 /* Allocate the IRP */
332 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
333
334 /* Set the IRP */
335 Irp->Tail.Overlay.OriginalFileObject = FileObject;
336 Irp->RequestorMode = ExGetPreviousMode();
337 Irp->UserIosb = &IoStatusBlock;
338 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
339 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
340 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
341
342 /* Set Stack Parameters */
343 StackPtr = IoGetNextIrpStackLocation(Irp);
344 StackPtr->FileObject = FileObject;
345
346 /* Set Parameters */
347 if (OperationCode == QuerySecurityDescriptor)
348 {
349 StackPtr->Parameters.QuerySecurity.SecurityInformation = SecurityInformation;
350 StackPtr->Parameters.QuerySecurity.Length = *BufferLength;
351 Irp->UserBuffer = SecurityDescriptor;
352 }
353 else
354 {
355 StackPtr->Parameters.SetSecurity.SecurityInformation = SecurityInformation;
356 StackPtr->Parameters.SetSecurity.SecurityDescriptor = SecurityDescriptor;
357 }
358
359 /* Call the Driver */
360 Status = IoCallDriver(FileObject->DeviceObject, Irp);
361
362 if (Status == STATUS_PENDING)
363 {
364 if (LocalEvent)
365 {
366 KeWaitForSingleObject(&Event,
367 Executive,
368 KernelMode,
369 FileObject->Flags & FO_ALERTABLE_IO,
370 NULL);
371 Status = IoStatusBlock.Status;
372 }
373 else
374 {
375 KeWaitForSingleObject(&FileObject->Event,
376 Executive,
377 KernelMode,
378 FileObject->Flags & FO_ALERTABLE_IO,
379 NULL);
380 Status = FileObject->FinalStatus;
381 }
382 }
383
384 /* This Driver doesn't implement Security, so try to give it a default */
385 if (Status == STATUS_INVALID_DEVICE_REQUEST)
386 {
387 if (OperationCode == QuerySecurityDescriptor)
388 {
389 /* Set a World Security Descriptor */
390 Status = SeSetWorldSecurityDescriptor(SecurityInformation,
391 SecurityDescriptor,
392 BufferLength);
393 }
394 else
395 {
396 /* It wasn't a query, so just fake success */
397 Status = STATUS_SUCCESS;
398 }
399 }
400 else if (OperationCode == QuerySecurityDescriptor)
401 {
402 /* Return length */
403 *BufferLength = IoStatusBlock.Information;
404 }
405
406 /* Return Status */
407 return Status;
408 }
409
410 NTSTATUS
411 STDCALL
412 IopQueryNameFile(PVOID ObjectBody,
413 POBJECT_NAME_INFORMATION ObjectNameInfo,
414 ULONG Length,
415 PULONG ReturnLength)
416 {
417 PVOID LocalInfo;
418 PFILE_OBJECT FileObject;
419 ULONG LocalReturnLength;
420 NTSTATUS Status;
421
422 DPRINT1("IopQueryNameFile() called\n");
423
424 FileObject = (PFILE_OBJECT)ObjectBody;
425
426 /* Allocate Buffer */
427 LocalInfo = ExAllocatePool(PagedPool,
428 sizeof(OBJECT_NAME_INFORMATION) +
429 MAX_PATH * sizeof(WCHAR));
430 if (LocalInfo == NULL) return STATUS_INSUFFICIENT_RESOURCES;
431
432 /* Query the name */
433 Status = ObQueryNameString(FileObject->DeviceObject,
434 LocalInfo,
435 MAX_PATH * sizeof(WCHAR),
436 &LocalReturnLength);
437 if (!NT_SUCCESS (Status))
438 {
439 ExFreePool (LocalInfo);
440 return Status;
441 }
442 DPRINT ("Device path: %wZ\n", &LocalInfo->Name);
443
444 /* Write Device Path */
445 Status = RtlAppendUnicodeStringToString(&ObjectNameInfo->Name,
446 &((POBJECT_NAME_INFORMATION)LocalInfo)->Name);
447
448 /* Query the File name */
449 Status = IoQueryFileInformation(FileObject,
450 FileNameInformation,
451 LocalReturnLength,
452 LocalInfo,
453 NULL);
454 if (Status != STATUS_SUCCESS)
455 {
456 ExFreePool(LocalInfo);
457 return Status;
458 }
459
460 /* Write the Name */
461 Status = RtlAppendUnicodeToString(&ObjectNameInfo->Name,
462 ((PFILE_NAME_INFORMATION)LocalInfo)->FileName);
463 DPRINT ("Total path: %wZ\n", &ObjectNameInfo->Name);
464
465 /* Free buffer and return */
466 ExFreePool(LocalInfo);
467 return Status;
468 }
469
470 VOID
471 STDCALL
472 IopCloseFile(PVOID ObjectBody,
473 ULONG HandleCount)
474 {
475 PFILE_OBJECT FileObject = (PFILE_OBJECT)ObjectBody;
476 KEVENT Event;
477 PIRP Irp;
478 PIO_STACK_LOCATION StackPtr;
479 NTSTATUS Status;
480 PDEVICE_OBJECT DeviceObject;
481
482 DPRINT("IopCloseFile()\n");
483
484 if (HandleCount > 1 || FileObject->DeviceObject == NULL) return;
485
486 /* Check if this is a direct open or not */
487 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
488 {
489 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
490 }
491 else
492 {
493 DeviceObject = IoGetRelatedDeviceObject(FileObject);
494 }
495
496 /* Clear and set up Events */
497 KeClearEvent(&FileObject->Event);
498 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
499
500 /* Allocate an IRP */
501 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
502
503 /* Set it up */
504 Irp->UserEvent = &Event;
505 Irp->UserIosb = &Irp->IoStatus;
506 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
507 Irp->Tail.Overlay.OriginalFileObject = FileObject;
508 Irp->Flags = IRP_CLOSE_OPERATION | IRP_SYNCHRONOUS_API;
509
510 /* Set up Stack Pointer Data */
511 StackPtr = IoGetNextIrpStackLocation(Irp);
512 StackPtr->MajorFunction = IRP_MJ_CLEANUP;
513 StackPtr->FileObject = FileObject;
514
515 /* Call the FS Driver */
516 Status = IoCallDriver(DeviceObject, Irp);
517
518 /* Wait for completion */
519 if (Status == STATUS_PENDING)
520 {
521 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
522 }
523 IoFreeIrp(Irp);
524 }
525
526 /* FUNCTIONS *****************************************************************/
527
528 /*
529 * @unimplemented
530 */
531 NTSTATUS
532 STDCALL
533 IoCheckQuerySetFileInformation(IN FILE_INFORMATION_CLASS FileInformationClass,
534 IN ULONG Length,
535 IN BOOLEAN SetOperation)
536 {
537 UNIMPLEMENTED;
538 return STATUS_NOT_IMPLEMENTED;
539 }
540
541 /*
542 * @unimplemented
543 */
544 NTSTATUS
545 STDCALL
546 IoCheckQuotaBufferValidity(IN PFILE_QUOTA_INFORMATION QuotaBuffer,
547 IN ULONG QuotaLength,
548 OUT PULONG ErrorOffset)
549 {
550 UNIMPLEMENTED;
551 return STATUS_NOT_IMPLEMENTED;
552 }
553
554 /*
555 * NAME EXPORTED
556 * IoCreateFile@56
557 *
558 * DESCRIPTION
559 * Either causes a new file or directory to be created, or it
560 * opens an existing file, device, directory or volume, giving
561 * the caller a handle for the file object. This handle can be
562 * used by subsequent calls to manipulate data within the file
563 * or the file object's state of attributes.
564 *
565 * ARGUMENTS
566 * FileHandle (OUT)
567 * Points to a variable which receives the file handle
568 * on return;
569 *
570 * DesiredAccess
571 * Desired access to the file;
572 *
573 * ObjectAttributes
574 * Structure describing the file;
575 *
576 * IoStatusBlock (OUT)
577 * Receives information about the operation on return;
578 *
579 * AllocationSize [OPTIONAL]
580 * Initial size of the file in bytes;
581 *
582 * FileAttributes
583 * Attributes to create the file with;
584 *
585 * ShareAccess
586 * Type of shared access the caller would like to the
587 * file;
588 *
589 * CreateDisposition
590 * Specifies what to do, depending on whether the
591 * file already exists;
592 *
593 * CreateOptions
594 * Options for creating a new file;
595 *
596 * EaBuffer [OPTIONAL]
597 * Undocumented;
598 *
599 * EaLength
600 * Undocumented;
601 *
602 * CreateFileType
603 * Type of file (normal, named pipe, mailslot) to create;
604 *
605 * ExtraCreateParameters [OPTIONAL]
606 * Additional creation data for named pipe and mailsots;
607 *
608 * Options
609 * Undocumented.
610 *
611 * RETURN VALUE
612 * Status
613 *
614 * NOTE
615 * Prototype taken from Bo Branten's ntifs.h v15.
616 * Description taken from old NtCreateFile's which is
617 * now a wrapper of this call.
618 *
619 * REVISIONS
620 *
621 * @implemented
622 */
623 NTSTATUS
624 STDCALL
625 IoCreateFile(OUT PHANDLE FileHandle,
626 IN ACCESS_MASK DesiredAccess,
627 IN POBJECT_ATTRIBUTES ObjectAttributes,
628 OUT PIO_STATUS_BLOCK IoStatusBlock,
629 IN PLARGE_INTEGER AllocationSize OPTIONAL,
630 IN ULONG FileAttributes,
631 IN ULONG ShareAccess,
632 IN ULONG CreateDisposition,
633 IN ULONG CreateOptions,
634 IN PVOID EaBuffer OPTIONAL,
635 IN ULONG EaLength,
636 IN CREATE_FILE_TYPE CreateFileType,
637 IN PVOID ExtraCreateParameters OPTIONAL,
638 IN ULONG Options)
639 {
640 PFILE_OBJECT FileObject = NULL;
641 PDEVICE_OBJECT DeviceObject;
642 PIRP Irp;
643 PIO_STACK_LOCATION StackLoc;
644 IO_SECURITY_CONTEXT SecurityContext;
645 KPROCESSOR_MODE AccessMode;
646 HANDLE LocalHandle;
647 IO_STATUS_BLOCK LocalIoStatusBlock;
648 LARGE_INTEGER SafeAllocationSize;
649 PVOID SystemEaBuffer = NULL;
650 NTSTATUS Status = STATUS_SUCCESS;
651
652 DPRINT("IoCreateFile(FileHandle %x, DesiredAccess %x, "
653 "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
654 FileHandle,DesiredAccess,ObjectAttributes,
655 ObjectAttributes->ObjectName->Buffer);
656
657 ASSERT_IRQL(PASSIVE_LEVEL);
658
659 if (IoStatusBlock == NULL || FileHandle == NULL)
660 return STATUS_ACCESS_VIOLATION;
661
662 LocalHandle = 0;
663
664 if(Options & IO_NO_PARAMETER_CHECKING)
665 AccessMode = KernelMode;
666 else
667 AccessMode = ExGetPreviousMode();
668
669 if(AccessMode != KernelMode)
670 {
671 _SEH_TRY
672 {
673 ProbeForWrite(FileHandle,
674 sizeof(HANDLE),
675 sizeof(ULONG));
676 ProbeForWrite(IoStatusBlock,
677 sizeof(IO_STATUS_BLOCK),
678 sizeof(ULONG));
679 if(AllocationSize != NULL)
680 {
681 ProbeForRead(AllocationSize,
682 sizeof(LARGE_INTEGER),
683 sizeof(ULONG));
684 SafeAllocationSize = *AllocationSize;
685 }
686 else
687 SafeAllocationSize.QuadPart = 0;
688
689 if(EaBuffer != NULL && EaLength > 0)
690 {
691 ProbeForRead(EaBuffer,
692 EaLength,
693 sizeof(ULONG));
694
695 /* marshal EaBuffer */
696 SystemEaBuffer = ExAllocatePool(NonPagedPool,
697 EaLength);
698 if(SystemEaBuffer == NULL)
699 {
700 Status = STATUS_INSUFFICIENT_RESOURCES;
701 _SEH_LEAVE;
702 }
703
704 RtlCopyMemory(SystemEaBuffer,
705 EaBuffer,
706 EaLength);
707 }
708 }
709 _SEH_HANDLE
710 {
711 Status = _SEH_GetExceptionCode();
712 }
713 _SEH_END;
714
715 if(!NT_SUCCESS(Status))
716 {
717 return Status;
718 }
719 }
720 else
721 {
722 if(AllocationSize != NULL)
723 SafeAllocationSize = *AllocationSize;
724 else
725 SafeAllocationSize.QuadPart = 0;
726
727 if(EaBuffer != NULL && EaLength > 0)
728 {
729 SystemEaBuffer = EaBuffer;
730 }
731 }
732
733 if(Options & IO_CHECK_CREATE_PARAMETERS)
734 {
735 DPRINT1("FIXME: IO_CHECK_CREATE_PARAMETERS not yet supported!\n");
736 }
737
738 if (CreateDisposition == FILE_OPEN ||
739 CreateDisposition == FILE_OPEN_IF)
740 {
741 Status = ObOpenObjectByName(ObjectAttributes,
742 NULL,
743 NULL,
744 AccessMode,
745 DesiredAccess,
746 NULL,
747 &LocalHandle);
748 if (NT_SUCCESS(Status))
749 {
750 Status = ObReferenceObjectByHandle(LocalHandle,
751 DesiredAccess,
752 NULL,
753 AccessMode,
754 (PVOID*)&DeviceObject,
755 NULL);
756 ZwClose(LocalHandle);
757 if (!NT_SUCCESS(Status))
758 {
759 return Status;
760 }
761 if (BODY_TO_HEADER(DeviceObject)->ObjectType != IoDeviceObjectType)
762 {
763 ObDereferenceObject (DeviceObject);
764 return STATUS_OBJECT_NAME_COLLISION;
765 }
766 /* FIXME: wt... */
767 FileObject = IoCreateStreamFileObject(NULL, DeviceObject);
768 ObDereferenceObject (DeviceObject);
769 }
770 }
771
772
773 if (FileObject == NULL)
774 {
775 Status = ObCreateObject(AccessMode,
776 IoFileObjectType,
777 ObjectAttributes,
778 AccessMode,
779 NULL,
780 sizeof(FILE_OBJECT),
781 0,
782 0,
783 (PVOID*)&FileObject);
784 if (!NT_SUCCESS(Status))
785 {
786 DPRINT("ObCreateObject() failed! (Status %lx)\n", Status);
787 return Status;
788 }
789 }
790 RtlMapGenericMask(&DesiredAccess,
791 BODY_TO_HEADER(FileObject)->ObjectType->Mapping);
792
793 Status = ObInsertObject ((PVOID)FileObject,
794 NULL,
795 DesiredAccess,
796 0,
797 NULL,
798 &LocalHandle);
799 if (!NT_SUCCESS(Status))
800 {
801 DPRINT("ObInsertObject() failed! (Status %lx)\n", Status);
802 ObDereferenceObject (FileObject);
803 return Status;
804 }
805
806 if (CreateOptions & FILE_SYNCHRONOUS_IO_ALERT)
807 {
808 FileObject->Flags |= (FO_ALERTABLE_IO | FO_SYNCHRONOUS_IO);
809 }
810 if (CreateOptions & FILE_SYNCHRONOUS_IO_NONALERT)
811 {
812 FileObject->Flags |= FO_SYNCHRONOUS_IO;
813 }
814
815 if (CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)
816 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING;
817
818 SecurityContext.SecurityQos = NULL; /* ?? */
819 SecurityContext.AccessState = NULL; /* ?? */
820 SecurityContext.DesiredAccess = DesiredAccess;
821 SecurityContext.FullCreateOptions = 0; /* ?? */
822
823 KeInitializeEvent(&FileObject->Lock, SynchronizationEvent, TRUE);
824 KeInitializeEvent(&FileObject->Event, NotificationEvent, FALSE);
825
826 DPRINT("FileObject %x\n", FileObject);
827 DPRINT("FileObject->DeviceObject %x\n", FileObject->DeviceObject);
828 /*
829 * Create a new IRP to hand to
830 * the FS driver: this may fail
831 * due to resource shortage.
832 */
833 Irp = IoAllocateIrp(FileObject->DeviceObject->StackSize, FALSE);
834 if (Irp == NULL)
835 {
836 ZwClose(LocalHandle);
837 return STATUS_UNSUCCESSFUL;
838 }
839
840 //trigger FileObject/Event dereferencing
841 Irp->Tail.Overlay.OriginalFileObject = FileObject;
842 Irp->RequestorMode = AccessMode;
843 Irp->UserIosb = &LocalIoStatusBlock;
844 Irp->AssociatedIrp.SystemBuffer = SystemEaBuffer;
845 Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
846 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
847 Irp->UserEvent = &FileObject->Event;
848 Irp->Overlay.AllocationSize = SafeAllocationSize;
849
850 /*
851 * Get the stack location for the new
852 * IRP and prepare it.
853 */
854 StackLoc = IoGetNextIrpStackLocation(Irp);
855 StackLoc->MinorFunction = 0;
856 StackLoc->Flags = (UCHAR)Options;
857 StackLoc->Control = 0;
858 StackLoc->DeviceObject = FileObject->DeviceObject;
859 StackLoc->FileObject = FileObject;
860
861 switch (CreateFileType)
862 {
863 default:
864 case CreateFileTypeNone:
865 StackLoc->MajorFunction = IRP_MJ_CREATE;
866 StackLoc->Parameters.Create.SecurityContext = &SecurityContext;
867 StackLoc->Parameters.Create.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
868 StackLoc->Parameters.Create.Options |= (CreateDisposition << 24);
869 StackLoc->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
870 StackLoc->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
871 StackLoc->Parameters.Create.EaLength = SystemEaBuffer != NULL ? EaLength : 0;
872 break;
873
874 case CreateFileTypeNamedPipe:
875 StackLoc->MajorFunction = IRP_MJ_CREATE_NAMED_PIPE;
876 StackLoc->Parameters.CreatePipe.SecurityContext = &SecurityContext;
877 StackLoc->Parameters.CreatePipe.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
878 StackLoc->Parameters.CreatePipe.Options |= (CreateDisposition << 24);
879 StackLoc->Parameters.CreatePipe.ShareAccess = (USHORT)ShareAccess;
880 StackLoc->Parameters.CreatePipe.Parameters = ExtraCreateParameters;
881 break;
882
883 case CreateFileTypeMailslot:
884 StackLoc->MajorFunction = IRP_MJ_CREATE_MAILSLOT;
885 StackLoc->Parameters.CreateMailslot.SecurityContext = &SecurityContext;
886 StackLoc->Parameters.CreateMailslot.Options = (CreateOptions & FILE_VALID_OPTION_FLAGS);
887 StackLoc->Parameters.CreateMailslot.Options |= (CreateDisposition << 24);
888 StackLoc->Parameters.CreateMailslot.ShareAccess = (USHORT)ShareAccess;
889 StackLoc->Parameters.CreateMailslot.Parameters = ExtraCreateParameters;
890 break;
891 }
892
893 /*
894 * Now call the driver and
895 * possibly wait if it can
896 * not complete the request
897 * immediately.
898 */
899 Status = IofCallDriver(FileObject->DeviceObject, Irp );
900 DPRINT("Status :%x\n", Status);
901
902 if (Status == STATUS_PENDING)
903 {
904 KeWaitForSingleObject(&FileObject->Event,
905 Executive,
906 AccessMode,
907 FALSE,
908 NULL);
909 Status = LocalIoStatusBlock.Status;
910 }
911 if (!NT_SUCCESS(Status))
912 {
913 DPRINT("Failing create request with status %x\n", Status);
914 FileObject->DeviceObject = NULL;
915 FileObject->Vpb = NULL;
916
917 ZwClose(LocalHandle);
918 }
919 else
920 {
921 _SEH_TRY
922 {
923 *FileHandle = LocalHandle;
924 *IoStatusBlock = LocalIoStatusBlock;
925 }
926 _SEH_HANDLE
927 {
928 Status = _SEH_GetExceptionCode();
929 }
930 _SEH_END;
931 }
932
933 /* cleanup EABuffer if captured */
934 if(AccessMode != KernelMode && SystemEaBuffer != NULL)
935 {
936 ExFreePool(SystemEaBuffer);
937 }
938
939 ASSERT_IRQL(PASSIVE_LEVEL);
940
941 DPRINT("Finished IoCreateFile() (*FileHandle) %x\n", (*FileHandle));
942
943 return Status;
944 }
945
946 /*
947 * @unimplemented
948 */
949 NTSTATUS
950 STDCALL
951 IoCreateFileSpecifyDeviceObjectHint(OUT PHANDLE FileHandle,
952 IN ACCESS_MASK DesiredAccess,
953 IN POBJECT_ATTRIBUTES ObjectAttributes,
954 OUT PIO_STATUS_BLOCK IoStatusBlock,
955 IN PLARGE_INTEGER AllocationSize OPTIONAL,
956 IN ULONG FileAttributes,
957 IN ULONG ShareAccess,
958 IN ULONG Disposition,
959 IN ULONG CreateOptions,
960 IN PVOID EaBuffer OPTIONAL,
961 IN ULONG EaLength,
962 IN CREATE_FILE_TYPE CreateFileType,
963 IN PVOID ExtraCreateParameters OPTIONAL,
964 IN ULONG Options,
965 IN PVOID DeviceObject)
966 {
967 UNIMPLEMENTED;
968 return STATUS_NOT_IMPLEMENTED;
969 }
970
971 /*
972 * NAME EXPORTED
973 * IoCreateStreamFileObject@8
974 *
975 * DESCRIPTION
976 *
977 * ARGUMENTS
978 * FileObject
979 * ?
980 *
981 * DeviceObject
982 * ?
983 *
984 * RETURN VALUE
985 *
986 * NOTE
987 *
988 * REVISIONS
989 *
990 * @implemented
991 */
992 PFILE_OBJECT
993 STDCALL
994 IoCreateStreamFileObject(PFILE_OBJECT FileObject,
995 PDEVICE_OBJECT DeviceObject)
996 {
997 PFILE_OBJECT CreatedFileObject;
998 NTSTATUS Status;
999
1000 /* FIXME: This function should call ObInsertObject. The "Lite" version
1001 doesnt. This function is also called from IoCreateFile for some
1002 reason. These hacks need to be removed.
1003 */
1004
1005 DPRINT("IoCreateStreamFileObject(FileObject %x, DeviceObject %x)\n",
1006 FileObject, DeviceObject);
1007 PAGED_CODE();
1008
1009 /* Create the File Object */
1010 Status = ObCreateObject(KernelMode,
1011 IoFileObjectType,
1012 NULL,
1013 KernelMode,
1014 NULL,
1015 sizeof(FILE_OBJECT),
1016 0,
1017 0,
1018 (PVOID*)&CreatedFileObject);
1019 if (!NT_SUCCESS(Status))
1020 {
1021 DPRINT1("Could not create FileObject\n");
1022 return (NULL);
1023 }
1024
1025 /* Choose Device Object */
1026 if (FileObject) DeviceObject = FileObject->DeviceObject;
1027 DPRINT("DeviceObject %x\n", DeviceObject);
1028
1029 /* HACK */
1030 DeviceObject = IoGetAttachedDevice(DeviceObject);
1031
1032 /* Set File Object Data */
1033 CreatedFileObject->DeviceObject = DeviceObject;
1034 CreatedFileObject->Vpb = DeviceObject->Vpb;
1035 CreatedFileObject->Type = IO_TYPE_FILE;
1036 /* HACK */
1037 CreatedFileObject->Flags |= FO_DIRECT_DEVICE_OPEN;
1038 //CreatedFileObject->Flags = FO_STREAM_FILE;
1039
1040 /* Initialize Lock and Event */
1041 KeInitializeEvent(&CreatedFileObject->Event, NotificationEvent, FALSE);
1042 KeInitializeEvent(&CreatedFileObject->Lock, SynchronizationEvent, TRUE);
1043
1044 /* Return file */
1045 return CreatedFileObject;
1046 }
1047
1048 /*
1049 * @unimplemented
1050 */
1051 PFILE_OBJECT
1052 STDCALL
1053 IoCreateStreamFileObjectEx(IN PFILE_OBJECT FileObject OPTIONAL,
1054 IN PDEVICE_OBJECT DeviceObject OPTIONAL,
1055 OUT PHANDLE FileObjectHandle OPTIONAL)
1056 {
1057 UNIMPLEMENTED;
1058 return 0;
1059 }
1060
1061 /*
1062 * @unimplemented
1063 */
1064 PFILE_OBJECT
1065 STDCALL
1066 IoCreateStreamFileObjectLite(IN PFILE_OBJECT FileObject OPTIONAL,
1067 IN PDEVICE_OBJECT DeviceObject OPTIONAL)
1068 {
1069 UNIMPLEMENTED;
1070 return 0;
1071 }
1072
1073 /*
1074 * @implemented
1075 */
1076 PGENERIC_MAPPING
1077 STDCALL
1078 IoGetFileObjectGenericMapping(VOID)
1079 {
1080 return &IopFileMapping;
1081 }
1082
1083 /*
1084 * @implemented
1085 */
1086 BOOLEAN
1087 STDCALL
1088 IoIsFileOriginRemote(IN PFILE_OBJECT FileObject)
1089 {
1090 /* Return the flag status */
1091 return (FileObject->Flags & FO_REMOTE_ORIGIN);
1092 }
1093
1094 /*
1095 * @unimplemented
1096 */
1097 NTSTATUS
1098 STDCALL
1099 IoQueryFileDosDeviceName(IN PFILE_OBJECT FileObject,
1100 OUT POBJECT_NAME_INFORMATION *ObjectNameInformation)
1101 {
1102 UNIMPLEMENTED;
1103 return STATUS_NOT_IMPLEMENTED;
1104 }
1105
1106 /*
1107 * @implemented
1108 */
1109 NTSTATUS
1110 STDCALL
1111 IoQueryFileInformation(IN PFILE_OBJECT FileObject,
1112 IN FILE_INFORMATION_CLASS FileInformationClass,
1113 IN ULONG Length,
1114 OUT PVOID FileInformation,
1115 OUT PULONG ReturnedLength)
1116 {
1117 IO_STATUS_BLOCK IoStatusBlock;
1118 PIRP Irp;
1119 PDEVICE_OBJECT DeviceObject;
1120 PIO_STACK_LOCATION StackPtr;
1121 BOOLEAN LocalEvent = FALSE;
1122 KEVENT Event;
1123 NTSTATUS Status;
1124
1125 ASSERT(FileInformation != NULL);
1126
1127 Status = ObReferenceObjectByPointer(FileObject,
1128 FILE_READ_ATTRIBUTES,
1129 IoFileObjectType,
1130 KernelMode);
1131 if (!NT_SUCCESS(Status)) return(Status);
1132
1133 DPRINT("FileObject %x\n", FileObject);
1134
1135 /* Get the Device Object */
1136 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1137
1138 /* Check if we should use Sync IO or not */
1139 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1140 {
1141 /* Use File Object event */
1142 KeClearEvent(&FileObject->Event);
1143 }
1144 else
1145 {
1146 /* Use local event */
1147 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1148 LocalEvent = TRUE;
1149 }
1150
1151 /* Allocate the IRP */
1152 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1153
1154 /* Set the IRP */
1155 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1156 Irp->RequestorMode = KernelMode;
1157 Irp->AssociatedIrp.SystemBuffer = FileInformation;
1158 Irp->UserIosb = &IoStatusBlock;
1159 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1160 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1161 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1162
1163 /* Set the Stack Data */
1164 StackPtr = IoGetNextIrpStackLocation(Irp);
1165 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
1166 StackPtr->FileObject = FileObject;
1167
1168 /* Set Parameters */
1169 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
1170 StackPtr->Parameters.QueryFile.Length = Length;
1171
1172 /* Call the Driver */
1173 Status = IoCallDriver(FileObject->DeviceObject, Irp);
1174
1175 if (Status == STATUS_PENDING)
1176 {
1177 if (LocalEvent)
1178 {
1179 KeWaitForSingleObject(&Event,
1180 Executive,
1181 KernelMode,
1182 FileObject->Flags & FO_ALERTABLE_IO,
1183 NULL);
1184 Status = IoStatusBlock.Status;
1185 }
1186 else
1187 {
1188 KeWaitForSingleObject(&FileObject->Event,
1189 Executive,
1190 KernelMode,
1191 FileObject->Flags & FO_ALERTABLE_IO,
1192 NULL);
1193 Status = FileObject->FinalStatus;
1194 }
1195 }
1196
1197
1198 /* Return the Length and Status. ReturnedLength is NOT optional */
1199 *ReturnedLength = IoStatusBlock.Information;
1200 return Status;
1201 }
1202
1203 /*
1204 * @unimplemented
1205 */
1206 NTSTATUS
1207 STDCALL
1208 IoSetFileOrigin(IN PFILE_OBJECT FileObject,
1209 IN BOOLEAN Remote)
1210 {
1211 UNIMPLEMENTED;
1212 return STATUS_NOT_IMPLEMENTED;
1213 }
1214
1215 /**
1216 * @name NtCancelIoFile
1217 *
1218 * Cancel all pending I/O operations in the current thread for specified
1219 * file object.
1220 *
1221 * @param FileHandle
1222 * Handle to file object to cancel requests for. No specific
1223 * access rights are needed.
1224 * @param IoStatusBlock
1225 * Pointer to status block which is filled with final completition
1226 * status on successful return.
1227 *
1228 * @return Status.
1229 *
1230 * @implemented
1231 */
1232 NTSTATUS
1233 STDCALL
1234 NtCancelIoFile(IN HANDLE FileHandle,
1235 OUT PIO_STATUS_BLOCK IoStatusBlock)
1236 {
1237 NTSTATUS Status;
1238 PFILE_OBJECT FileObject;
1239 PETHREAD Thread;
1240 PLIST_ENTRY IrpEntry;
1241 PIRP Irp;
1242 KIRQL OldIrql;
1243 BOOLEAN OurIrpsInList = FALSE;
1244 LARGE_INTEGER Interval;
1245
1246 if ((ULONG_PTR)IoStatusBlock >= MmUserProbeAddress &&
1247 KeGetPreviousMode() == UserMode)
1248 return STATUS_ACCESS_VIOLATION;
1249
1250 Status = ObReferenceObjectByHandle(FileHandle, 0, IoFileObjectType,
1251 KeGetPreviousMode(), (PVOID*)&FileObject,
1252 NULL);
1253 if (!NT_SUCCESS(Status))
1254 return Status;
1255
1256 /* IRP cancellations are synchronized at APC_LEVEL. */
1257 OldIrql = KfRaiseIrql(APC_LEVEL);
1258
1259 /*
1260 * Walk the list of active IRPs and cancel the ones that belong to
1261 * our file object.
1262 */
1263
1264 Thread = PsGetCurrentThread();
1265 for (IrpEntry = Thread->IrpList.Flink;
1266 IrpEntry != &Thread->IrpList;
1267 IrpEntry = IrpEntry->Flink)
1268 {
1269 Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
1270 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
1271 {
1272 IoCancelIrp(Irp);
1273 /* Don't break here, we want to cancel all IRPs for the file object. */
1274 OurIrpsInList = TRUE;
1275 }
1276 }
1277
1278 KfLowerIrql(OldIrql);
1279
1280 while (OurIrpsInList)
1281 {
1282 OurIrpsInList = FALSE;
1283
1284 /* Wait a short while and then look if all our IRPs were completed. */
1285 Interval.QuadPart = -1000000; /* 100 milliseconds */
1286 KeDelayExecutionThread(KernelMode, FALSE, &Interval);
1287
1288 OldIrql = KfRaiseIrql(APC_LEVEL);
1289
1290 /*
1291 * Look in the list if all IRPs for the specified file object
1292 * are completed (or cancelled). If someone sends a new IRP
1293 * for our file object while we're here we can happily loop
1294 * forever.
1295 */
1296
1297 for (IrpEntry = Thread->IrpList.Flink;
1298 IrpEntry != &Thread->IrpList;
1299 IrpEntry = IrpEntry->Flink)
1300 {
1301 Irp = CONTAINING_RECORD(IrpEntry, IRP, ThreadListEntry);
1302 if (Irp->Tail.Overlay.OriginalFileObject == FileObject)
1303 {
1304 OurIrpsInList = TRUE;
1305 break;
1306 }
1307 }
1308
1309 KfLowerIrql(OldIrql);
1310 }
1311
1312 _SEH_TRY
1313 {
1314 IoStatusBlock->Status = STATUS_SUCCESS;
1315 IoStatusBlock->Information = 0;
1316 Status = STATUS_SUCCESS;
1317 }
1318 _SEH_HANDLE
1319 {
1320 Status = STATUS_UNSUCCESSFUL;
1321 }
1322 _SEH_END;
1323
1324 ObDereferenceObject(FileObject);
1325
1326 return Status;
1327 }
1328
1329 /*
1330 * NAME EXPORTED
1331 * NtCreateFile@44
1332 *
1333 * DESCRIPTION
1334 * Entry point to call IoCreateFile with
1335 * default parameters.
1336 *
1337 * ARGUMENTS
1338 * See IoCreateFile.
1339 *
1340 * RETURN VALUE
1341 * See IoCreateFile.
1342 *
1343 * REVISIONS
1344 * 2000-03-25 (ea)
1345 * Code originally in NtCreateFile moved in IoCreateFile.
1346 *
1347 * @implemented
1348 */
1349 NTSTATUS
1350 STDCALL
1351 NtCreateFile(PHANDLE FileHandle,
1352 ACCESS_MASK DesiredAccess,
1353 POBJECT_ATTRIBUTES ObjectAttributes,
1354 PIO_STATUS_BLOCK IoStatusBlock,
1355 PLARGE_INTEGER AllocateSize,
1356 ULONG FileAttributes,
1357 ULONG ShareAccess,
1358 ULONG CreateDisposition,
1359 ULONG CreateOptions,
1360 PVOID EaBuffer,
1361 ULONG EaLength)
1362 {
1363 /* Call the I/O Function */
1364 return IoCreateFile(FileHandle,
1365 DesiredAccess,
1366 ObjectAttributes,
1367 IoStatusBlock,
1368 AllocateSize,
1369 FileAttributes,
1370 ShareAccess,
1371 CreateDisposition,
1372 CreateOptions,
1373 EaBuffer,
1374 EaLength,
1375 CreateFileTypeNone,
1376 NULL,
1377 0);
1378 }
1379
1380 NTSTATUS
1381 STDCALL
1382 NtCreateMailslotFile(OUT PHANDLE FileHandle,
1383 IN ACCESS_MASK DesiredAccess,
1384 IN POBJECT_ATTRIBUTES ObjectAttributes,
1385 OUT PIO_STATUS_BLOCK IoStatusBlock,
1386 IN ULONG CreateOptions,
1387 IN ULONG MailslotQuota,
1388 IN ULONG MaxMessageSize,
1389 IN PLARGE_INTEGER TimeOut)
1390 {
1391 MAILSLOT_CREATE_PARAMETERS Buffer;
1392
1393 DPRINT("NtCreateMailslotFile(FileHandle %x, DesiredAccess %x, "
1394 "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
1395 FileHandle,DesiredAccess,ObjectAttributes,
1396 ObjectAttributes->ObjectName->Buffer);
1397 PAGED_CODE();
1398
1399 /* Check for Timeout */
1400 if (TimeOut)
1401 {
1402 /* Enable it */
1403 Buffer.TimeoutSpecified = TRUE;
1404
1405 /* FIXME: Add SEH */
1406 Buffer.ReadTimeout = *TimeOut;
1407 }
1408 else
1409 {
1410 /* No timeout */
1411 Buffer.TimeoutSpecified = FALSE;
1412 }
1413
1414 /* Set Settings */
1415 Buffer.MailslotQuota = MailslotQuota;
1416 Buffer.MaximumMessageSize = MaxMessageSize;
1417
1418 /* Call I/O */
1419 return IoCreateFile(FileHandle,
1420 DesiredAccess,
1421 ObjectAttributes,
1422 IoStatusBlock,
1423 NULL,
1424 FILE_ATTRIBUTE_NORMAL,
1425 FILE_SHARE_READ | FILE_SHARE_WRITE,
1426 FILE_CREATE,
1427 CreateOptions,
1428 NULL,
1429 0,
1430 CreateFileTypeMailslot,
1431 (PVOID)&Buffer,
1432 0);
1433 }
1434
1435 NTSTATUS
1436 STDCALL
1437 NtCreateNamedPipeFile(PHANDLE FileHandle,
1438 ACCESS_MASK DesiredAccess,
1439 POBJECT_ATTRIBUTES ObjectAttributes,
1440 PIO_STATUS_BLOCK IoStatusBlock,
1441 ULONG ShareAccess,
1442 ULONG CreateDisposition,
1443 ULONG CreateOptions,
1444 ULONG NamedPipeType,
1445 ULONG ReadMode,
1446 ULONG CompletionMode,
1447 ULONG MaximumInstances,
1448 ULONG InboundQuota,
1449 ULONG OutboundQuota,
1450 PLARGE_INTEGER DefaultTimeout)
1451 {
1452 NAMED_PIPE_CREATE_PARAMETERS Buffer;
1453
1454 DPRINT("NtCreateNamedPipeFile(FileHandle %x, DesiredAccess %x, "
1455 "ObjectAttributes %x ObjectAttributes->ObjectName->Buffer %S)\n",
1456 FileHandle,DesiredAccess,ObjectAttributes,
1457 ObjectAttributes->ObjectName->Buffer);
1458 PAGED_CODE();
1459
1460 /* Check for Timeout */
1461 if (DefaultTimeout)
1462 {
1463 /* Enable it */
1464 Buffer.TimeoutSpecified = TRUE;
1465
1466 /* FIXME: Add SEH */
1467 Buffer.DefaultTimeout = *DefaultTimeout;
1468 }
1469 else
1470 {
1471 /* No timeout */
1472 Buffer.TimeoutSpecified = FALSE;
1473 }
1474
1475 /* Set Settings */
1476 Buffer.NamedPipeType = NamedPipeType;
1477 Buffer.ReadMode = ReadMode;
1478 Buffer.CompletionMode = CompletionMode;
1479 Buffer.MaximumInstances = MaximumInstances;
1480 Buffer.InboundQuota = InboundQuota;
1481 Buffer.OutboundQuota = OutboundQuota;
1482
1483 /* Call I/O */
1484 return IoCreateFile(FileHandle,
1485 DesiredAccess,
1486 ObjectAttributes,
1487 IoStatusBlock,
1488 NULL,
1489 FILE_ATTRIBUTE_NORMAL,
1490 ShareAccess,
1491 CreateDisposition,
1492 CreateOptions,
1493 NULL,
1494 0,
1495 CreateFileTypeNamedPipe,
1496 (PVOID)&Buffer,
1497 0);
1498 }
1499
1500 /*
1501 * NAME EXPORTED
1502 * NtDeleteFile@4
1503 *
1504 * DESCRIPTION
1505 *
1506 * ARGUMENTS
1507 * ObjectAttributes
1508 * ?
1509 *
1510 * RETURN VALUE
1511 *
1512 * REVISIONS
1513 *
1514 * @unimplemented
1515 */
1516 NTSTATUS
1517 STDCALL
1518 NtDeleteFile(IN POBJECT_ATTRIBUTES ObjectAttributes)
1519 {
1520 UNIMPLEMENTED;
1521 return(STATUS_NOT_IMPLEMENTED);
1522 }
1523
1524 NTSTATUS
1525 STDCALL
1526 NtFlushWriteBuffer(VOID)
1527 {
1528 KeFlushWriteBuffer();
1529 return STATUS_SUCCESS;
1530 }
1531
1532 /*
1533 * FUNCTION: Flushes cached file data to disk
1534 * ARGUMENTS:
1535 * FileHandle = Points to the file
1536 * IoStatusBlock = Caller must supply storage to receive the result of
1537 * the flush buffers operation. The information field is
1538 * set to number of bytes flushed to disk.
1539 * RETURNS: Status
1540 * REMARKS: This function maps to the win32 FlushFileBuffers
1541 */
1542 NTSTATUS
1543 STDCALL
1544 NtFlushBuffersFile(IN HANDLE FileHandle,
1545 OUT PIO_STATUS_BLOCK IoStatusBlock)
1546 {
1547 PFILE_OBJECT FileObject = NULL;
1548 PIRP Irp;
1549 PIO_STACK_LOCATION StackPtr;
1550 NTSTATUS Status;
1551 PDEVICE_OBJECT DeviceObject;
1552 KEVENT Event;
1553 BOOLEAN LocalEvent = FALSE;
1554 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1555
1556 /* Get the File Object */
1557 Status = ObReferenceObjectByHandle(FileHandle,
1558 FILE_WRITE_DATA,
1559 NULL,
1560 PreviousMode,
1561 (PVOID*)&FileObject,
1562 NULL);
1563 if (Status != STATUS_SUCCESS) return(Status);
1564
1565 /* Check if this is a direct open or not */
1566 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
1567 {
1568 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
1569 }
1570 else
1571 {
1572 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1573 }
1574
1575 /* Check if we should use Sync IO or not */
1576 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
1577 {
1578 /* Use File Object event */
1579 KeClearEvent(&FileObject->Event);
1580 }
1581 else
1582 {
1583 /* Use local event */
1584 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
1585 LocalEvent = TRUE;
1586 }
1587
1588 /* Allocate the IRP */
1589 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE)))
1590 {
1591 ObDereferenceObject(FileObject);
1592 return STATUS_INSUFFICIENT_RESOURCES;
1593 }
1594
1595 /* Set up the IRP */
1596 Irp->Flags = (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
1597 Irp->RequestorMode = PreviousMode;
1598 Irp->UserIosb = IoStatusBlock;
1599 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
1600 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1601 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1602
1603 /* Set up Stack Data */
1604 StackPtr = IoGetNextIrpStackLocation(Irp);
1605 StackPtr->MajorFunction = IRP_MJ_FLUSH_BUFFERS;
1606 StackPtr->FileObject = FileObject;
1607
1608 /* Call the Driver */
1609 Status = IoCallDriver(DeviceObject, Irp);
1610 if (Status == STATUS_PENDING)
1611 {
1612 if (LocalEvent)
1613 {
1614 KeWaitForSingleObject(&Event,
1615 Executive,
1616 PreviousMode,
1617 FileObject->Flags & FO_ALERTABLE_IO,
1618 NULL);
1619 Status = IoStatusBlock->Status;
1620 }
1621 else
1622 {
1623 KeWaitForSingleObject(&FileObject->Event,
1624 Executive,
1625 PreviousMode,
1626 FileObject->Flags & FO_ALERTABLE_IO,
1627 NULL);
1628 Status = FileObject->FinalStatus;
1629 }
1630 }
1631
1632 /* Return the Status */
1633 return Status;
1634 }
1635
1636 /*
1637 * @implemented
1638 */
1639 NTSTATUS
1640 STDCALL
1641 NtNotifyChangeDirectoryFile(IN HANDLE FileHandle,
1642 IN HANDLE Event OPTIONAL,
1643 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1644 IN PVOID ApcContext OPTIONAL,
1645 OUT PIO_STATUS_BLOCK IoStatusBlock,
1646 OUT PVOID Buffer,
1647 IN ULONG BufferSize,
1648 IN ULONG CompletionFilter,
1649 IN BOOLEAN WatchTree)
1650 {
1651 PIRP Irp;
1652 PDEVICE_OBJECT DeviceObject;
1653 PFILE_OBJECT FileObject;
1654 PIO_STACK_LOCATION IoStack;
1655 KPROCESSOR_MODE PreviousMode;
1656 NTSTATUS Status = STATUS_SUCCESS;
1657
1658 DPRINT("NtNotifyChangeDirectoryFile()\n");
1659
1660 PAGED_CODE();
1661
1662 PreviousMode = ExGetPreviousMode();
1663
1664 if(PreviousMode != KernelMode)
1665 {
1666 _SEH_TRY
1667 {
1668 ProbeForWrite(IoStatusBlock,
1669 sizeof(IO_STATUS_BLOCK),
1670 sizeof(ULONG));
1671 if(BufferSize != 0)
1672 {
1673 ProbeForWrite(Buffer,
1674 BufferSize,
1675 sizeof(ULONG));
1676 }
1677 }
1678 _SEH_HANDLE
1679 {
1680 Status = _SEH_GetExceptionCode();
1681 }
1682 _SEH_END;
1683
1684 if(!NT_SUCCESS(Status))
1685 {
1686 return Status;
1687 }
1688 }
1689
1690 Status = ObReferenceObjectByHandle(FileHandle,
1691 FILE_LIST_DIRECTORY,
1692 IoFileObjectType,
1693 PreviousMode,
1694 (PVOID *)&FileObject,
1695 NULL);
1696 if (Status != STATUS_SUCCESS) return(Status);
1697
1698
1699 DeviceObject = FileObject->DeviceObject;
1700
1701
1702 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
1703 if (Irp==NULL)
1704 {
1705 ObDereferenceObject(FileObject);
1706 return STATUS_UNSUCCESSFUL;
1707 }
1708
1709 if (Event == NULL)
1710 {
1711 Event = &FileObject->Event;
1712 }
1713
1714 /* Trigger FileObject/Event dereferencing */
1715 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1716 Irp->RequestorMode = PreviousMode;
1717 Irp->UserIosb = IoStatusBlock;
1718 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1719 Irp->UserEvent = Event;
1720 KeResetEvent( Event );
1721 Irp->UserBuffer = Buffer;
1722 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1723 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1724
1725 IoStack = IoGetNextIrpStackLocation(Irp);
1726
1727 IoStack->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
1728 IoStack->MinorFunction = IRP_MN_NOTIFY_CHANGE_DIRECTORY;
1729 IoStack->Flags = 0;
1730 IoStack->Control = 0;
1731 IoStack->DeviceObject = DeviceObject;
1732 IoStack->FileObject = FileObject;
1733
1734 if (WatchTree)
1735 {
1736 IoStack->Flags = SL_WATCH_TREE;
1737 }
1738
1739 IoStack->Parameters.NotifyDirectory.CompletionFilter = CompletionFilter;
1740 IoStack->Parameters.NotifyDirectory.Length = BufferSize;
1741
1742 Status = IoCallDriver(FileObject->DeviceObject,Irp);
1743
1744 /* FIXME: Should we wait here or not for synchronously opened files? */
1745
1746 return Status;
1747 }
1748
1749 /*
1750 * @unimplemented
1751 */
1752 NTSTATUS
1753 STDCALL
1754 NtLockFile(IN HANDLE FileHandle,
1755 IN HANDLE EventHandle OPTIONAL,
1756 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
1757 IN PVOID ApcContext OPTIONAL,
1758 OUT PIO_STATUS_BLOCK IoStatusBlock,
1759 IN PLARGE_INTEGER ByteOffset,
1760 IN PLARGE_INTEGER Length,
1761 IN PULONG Key,
1762 IN BOOLEAN FailImmediatedly,
1763 IN BOOLEAN ExclusiveLock
1764 )
1765 {
1766 PFILE_OBJECT FileObject = NULL;
1767 PLARGE_INTEGER LocalLength = NULL;
1768 PKEVENT Event = NULL;
1769 PIRP Irp = NULL;
1770 PIO_STACK_LOCATION StackPtr;
1771 PDEVICE_OBJECT DeviceObject;
1772 KPROCESSOR_MODE PreviousMode;
1773 NTSTATUS Status;
1774
1775 // FIXME: instead of this, use SEH when available?
1776 if (!Length || !ByteOffset)
1777 {
1778 Status = STATUS_INVALID_PARAMETER;
1779 goto fail;
1780 }
1781
1782 PreviousMode = ExGetPreviousMode();
1783
1784 Status = ObReferenceObjectByHandle(FileHandle,
1785 0,
1786 IoFileObjectType,
1787 PreviousMode,
1788 (PVOID*)&FileObject,
1789 NULL);
1790 if (!NT_SUCCESS(Status))
1791 {
1792 goto fail;
1793 }
1794
1795 DeviceObject = IoGetRelatedDeviceObject(FileObject);
1796
1797 Irp = IoAllocateIrp(DeviceObject->StackSize,
1798 TRUE);
1799 if (Irp == NULL)
1800 {
1801 Status = STATUS_INSUFFICIENT_RESOURCES;
1802 goto fail;
1803 }
1804
1805 if (EventHandle != NULL && !FailImmediatedly)
1806 {
1807 Status = ObReferenceObjectByHandle(EventHandle,
1808 SYNCHRONIZE,
1809 ExEventObjectType,
1810 PreviousMode,
1811 (PVOID*)&Event,
1812 NULL);
1813 if (!NT_SUCCESS(Status))
1814 {
1815 goto fail;
1816 }
1817 }
1818 else
1819 {
1820 Event = &FileObject->Event;
1821 KeResetEvent(Event);
1822 }
1823
1824 /* Trigger FileObject/Event dereferencing */
1825 Irp->Tail.Overlay.OriginalFileObject = FileObject;
1826
1827 Irp->RequestorMode = PreviousMode;
1828 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
1829 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
1830
1831 Irp->UserEvent = Event;
1832 Irp->UserIosb = IoStatusBlock;
1833 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
1834
1835 StackPtr = IoGetNextIrpStackLocation(Irp);
1836 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
1837 StackPtr->MinorFunction = IRP_MN_LOCK;
1838 StackPtr->FileObject = FileObject;
1839
1840 if (ExclusiveLock)
1841 StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
1842
1843 if (FailImmediatedly)
1844 StackPtr->Flags |= SL_FAIL_IMMEDIATELY;
1845
1846 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
1847 sizeof(LARGE_INTEGER),
1848 TAG_LOCK);
1849 if (!LocalLength)
1850 {
1851 Status = STATUS_INSUFFICIENT_RESOURCES;
1852 goto fail;
1853 }
1854
1855 *LocalLength = *Length;
1856
1857 StackPtr->Parameters.LockControl.Length = LocalLength;
1858 StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
1859 StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
1860
1861 IoSetCompletionRoutine(Irp,
1862 IopLockFileCompletionRoutine,
1863 LocalLength,
1864 TRUE,
1865 TRUE,
1866 TRUE);
1867
1868 /* Can't touch FileObject after IoCallDriver since it might be freed */
1869 Status = IofCallDriver(DeviceObject, Irp);
1870 if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO))
1871 {
1872 Status = KeWaitForSingleObject(Event,
1873 Executive,
1874 PreviousMode,
1875 FileObject->Flags & FO_ALERTABLE_IO,
1876 NULL);
1877
1878 if (Status != STATUS_WAIT_0)
1879 {
1880 DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n");
1881 /*
1882 * FIXME: Should do some special processing here if alertable wait
1883 * was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC)
1884 */
1885 return Status; /* Set status to something else? */
1886 }
1887
1888 Status = IoStatusBlock->Status;
1889 }
1890
1891 return Status;
1892
1893 fail:;
1894 if (LocalLength)
1895 ExFreePool(LocalLength);
1896
1897 if (Irp)
1898 IoFreeIrp(Irp);
1899
1900 if (Event)
1901 ObDereferenceObject(Event);
1902
1903 if (FileObject)
1904 ObDereferenceObject(FileObject);
1905
1906 return Status;
1907 }
1908
1909 /*
1910 * NAME EXPORTED
1911 * NtOpenFile@24
1912 *
1913 * DESCRIPTION
1914 * Opens an existing file (simpler than NtCreateFile).
1915 *
1916 * ARGUMENTS
1917 * FileHandle (OUT)
1918 * Variable that receives the file handle on return;
1919 *
1920 * DesiredAccess
1921 * Access desired by the caller to the file;
1922 *
1923 * ObjectAttributes
1924 * Structue describing the file to be opened;
1925 *
1926 * IoStatusBlock (OUT)
1927 * Receives details about the result of the
1928 * operation;
1929 *
1930 * ShareAccess
1931 * Type of shared access the caller requires;
1932 *
1933 * OpenOptions
1934 * Options for the file open.
1935 *
1936 * RETURN VALUE
1937 * Status.
1938 *
1939 * NOTE
1940 * Undocumented.
1941 *
1942 * @implemented
1943 */
1944 NTSTATUS
1945 STDCALL
1946 NtOpenFile(PHANDLE FileHandle,
1947 ACCESS_MASK DesiredAccess,
1948 POBJECT_ATTRIBUTES ObjectAttributes,
1949 PIO_STATUS_BLOCK IoStatusBlock,
1950 ULONG ShareAccess,
1951 ULONG OpenOptions)
1952 {
1953 /* Call the I/O Function */
1954 return IoCreateFile(FileHandle,
1955 DesiredAccess,
1956 ObjectAttributes,
1957 IoStatusBlock,
1958 NULL,
1959 0,
1960 ShareAccess,
1961 FILE_OPEN,
1962 OpenOptions,
1963 NULL,
1964 0,
1965 CreateFileTypeNone,
1966 NULL,
1967 0);
1968 }
1969
1970 NTSTATUS
1971 STDCALL
1972 NtQueryAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
1973 OUT PFILE_BASIC_INFORMATION FileInformation)
1974 {
1975 IO_STATUS_BLOCK IoStatusBlock;
1976 HANDLE FileHandle;
1977 NTSTATUS Status;
1978
1979 /* Open the file */
1980 Status = ZwOpenFile(&FileHandle,
1981 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
1982 ObjectAttributes,
1983 &IoStatusBlock,
1984 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1985 FILE_SYNCHRONOUS_IO_NONALERT);
1986 if (!NT_SUCCESS (Status))
1987 {
1988 DPRINT ("ZwOpenFile() failed (Status %lx)\n", Status);
1989 return Status;
1990 }
1991
1992 /* Get file attributes */
1993 Status = ZwQueryInformationFile(FileHandle,
1994 &IoStatusBlock,
1995 FileInformation,
1996 sizeof(FILE_BASIC_INFORMATION),
1997 FileBasicInformation);
1998 if (!NT_SUCCESS (Status))
1999 {
2000 DPRINT ("ZwQueryInformationFile() failed (Status %lx)\n", Status);
2001 }
2002
2003 ZwClose(FileHandle);
2004 return Status;
2005 }
2006
2007 /*
2008 * @implemented
2009 *
2010 * FUNCTION: Queries a directory file.
2011 * ARGUMENTS:
2012 * FileHandle = Handle to a directory file
2013 * EventHandle = Handle to the event signaled on completion
2014 * ApcRoutine = Asynchroneous procedure callback, called on completion
2015 * ApcContext = Argument to the apc.
2016 * IoStatusBlock = Caller supplies storage for extended status information.
2017 * FileInformation = Caller supplies storage for the resulting information.
2018 *
2019 * FileNameInformation FILE_NAMES_INFORMATION
2020 * FileDirectoryInformation FILE_DIRECTORY_INFORMATION
2021 * FileFullDirectoryInformation FILE_FULL_DIRECTORY_INFORMATION
2022 * FileBothDirectoryInformation FILE_BOTH_DIR_INFORMATION
2023 *
2024 * Length = Size of the storage supplied
2025 * FileInformationClass = Indicates the type of information requested.
2026 * ReturnSingleEntry = Specify true if caller only requests the first
2027 * directory found.
2028 * FileName = Initial directory name to query, that may contain wild
2029 * cards.
2030 * RestartScan = Number of times the action should be repeated
2031 * RETURNS: Status [ STATUS_SUCCESS, STATUS_ACCESS_DENIED, STATUS_INSUFFICIENT_RESOURCES,
2032 * STATUS_INVALID_PARAMETER, STATUS_INVALID_DEVICE_REQUEST, STATUS_BUFFER_OVERFLOW,
2033 * STATUS_INVALID_INFO_CLASS, STATUS_NO_SUCH_FILE, STATUS_NO_MORE_FILES ]
2034 */
2035 NTSTATUS
2036 STDCALL
2037 NtQueryDirectoryFile(IN HANDLE FileHandle,
2038 IN HANDLE PEvent OPTIONAL,
2039 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2040 IN PVOID ApcContext OPTIONAL,
2041 OUT PIO_STATUS_BLOCK IoStatusBlock,
2042 OUT PVOID FileInformation,
2043 IN ULONG Length,
2044 IN FILE_INFORMATION_CLASS FileInformationClass,
2045 IN BOOLEAN ReturnSingleEntry,
2046 IN PUNICODE_STRING FileName OPTIONAL,
2047 IN BOOLEAN RestartScan)
2048 {
2049 PIRP Irp;
2050 PDEVICE_OBJECT DeviceObject;
2051 PFILE_OBJECT FileObject;
2052 PIO_STACK_LOCATION StackPtr;
2053 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2054 NTSTATUS Status = STATUS_SUCCESS;
2055 BOOLEAN LocalEvent = FALSE;
2056 PKEVENT Event = NULL;
2057
2058 DPRINT("NtQueryDirectoryFile()\n");
2059 PAGED_CODE();
2060
2061 /* Validate User-Mode Buffers */
2062 if(PreviousMode != KernelMode)
2063 {
2064 _SEH_TRY
2065 {
2066 ProbeForWrite(IoStatusBlock,
2067 sizeof(IO_STATUS_BLOCK),
2068 sizeof(ULONG));
2069 ProbeForWrite(FileInformation,
2070 Length,
2071 sizeof(ULONG));
2072 }
2073 _SEH_HANDLE
2074 {
2075 Status = _SEH_GetExceptionCode();
2076 }
2077 _SEH_END;
2078
2079 if(!NT_SUCCESS(Status)) return Status;
2080 }
2081
2082 /* Get File Object */
2083 Status = ObReferenceObjectByHandle(FileHandle,
2084 FILE_LIST_DIRECTORY,
2085 IoFileObjectType,
2086 PreviousMode,
2087 (PVOID *)&FileObject,
2088 NULL);
2089 if (Status != STATUS_SUCCESS) return(Status);
2090
2091 /* Get Event Object */
2092 if (PEvent)
2093 {
2094 Status = ObReferenceObjectByHandle(PEvent,
2095 EVENT_MODIFY_STATE,
2096 ExEventObjectType,
2097 PreviousMode,
2098 (PVOID *)&Event,
2099 NULL);
2100 if (Status != STATUS_SUCCESS) return(Status);
2101 KeClearEvent(Event);
2102 }
2103
2104 /* Check if this is a direct open or not */
2105 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2106 {
2107 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2108 }
2109 else
2110 {
2111 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2112 }
2113
2114 /* Check if we should use Sync IO or not */
2115 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2116 {
2117 /* Use File Object event */
2118 KeClearEvent(&FileObject->Event);
2119 }
2120 else
2121 {
2122 LocalEvent = TRUE;
2123 }
2124
2125 /* Allocate the IRP */
2126 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE)))
2127 {
2128 ObDereferenceObject(FileObject);
2129 return STATUS_INSUFFICIENT_RESOURCES;
2130 }
2131
2132 /* Set up the IRP */
2133 Irp->RequestorMode = PreviousMode;
2134 Irp->UserIosb = IoStatusBlock;
2135 Irp->UserEvent = Event;
2136 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2137 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2138 Irp->UserBuffer = FileInformation;
2139 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2140 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2141
2142 /* Set up Stack Data */
2143 StackPtr = IoGetNextIrpStackLocation(Irp);
2144 StackPtr->FileObject = FileObject;
2145 StackPtr->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
2146 StackPtr->MinorFunction = IRP_MN_QUERY_DIRECTORY;
2147
2148 /* Set Parameters */
2149 StackPtr->Parameters.QueryDirectory.FileInformationClass = FileInformationClass;
2150 StackPtr->Parameters.QueryDirectory.FileName = FileName;
2151 StackPtr->Parameters.QueryDirectory.FileIndex = 0;
2152 StackPtr->Parameters.QueryDirectory.Length = Length;
2153 StackPtr->Flags = 0;
2154 if (RestartScan) StackPtr->Flags = SL_RESTART_SCAN;
2155 if (ReturnSingleEntry) StackPtr->Flags |= SL_RETURN_SINGLE_ENTRY;
2156
2157 /* Call the Driver */
2158 Status = IoCallDriver(DeviceObject, Irp);
2159 if (Status == STATUS_PENDING)
2160 {
2161 if (!LocalEvent)
2162 {
2163 KeWaitForSingleObject(&FileObject->Event,
2164 Executive,
2165 PreviousMode,
2166 FileObject->Flags & FO_ALERTABLE_IO,
2167 NULL);
2168 Status = FileObject->FinalStatus;
2169 }
2170 }
2171
2172 /* Return the Status */
2173 return Status;
2174 }
2175
2176 /*
2177 * @unimplemented
2178 */
2179 NTSTATUS STDCALL
2180 NtQueryEaFile(IN HANDLE FileHandle,
2181 OUT PIO_STATUS_BLOCK IoStatusBlock,
2182 OUT PVOID Buffer,
2183 IN ULONG Length,
2184 IN BOOLEAN ReturnSingleEntry,
2185 IN PVOID EaList OPTIONAL,
2186 IN ULONG EaListLength,
2187 IN PULONG EaIndex OPTIONAL,
2188 IN BOOLEAN RestartScan)
2189 {
2190 UNIMPLEMENTED;
2191 return STATUS_NOT_IMPLEMENTED;
2192 }
2193
2194 NTSTATUS
2195 STDCALL
2196 NtQueryFullAttributesFile(IN POBJECT_ATTRIBUTES ObjectAttributes,
2197 OUT PFILE_NETWORK_OPEN_INFORMATION FileInformation)
2198 {
2199 IO_STATUS_BLOCK IoStatusBlock;
2200 HANDLE FileHandle;
2201 NTSTATUS Status;
2202
2203 /* Open the file */
2204 Status = ZwOpenFile(&FileHandle,
2205 SYNCHRONIZE | FILE_READ_ATTRIBUTES,
2206 ObjectAttributes,
2207 &IoStatusBlock,
2208 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
2209 FILE_SYNCHRONOUS_IO_NONALERT);
2210 if (!NT_SUCCESS (Status))
2211 {
2212 DPRINT ("ZwOpenFile() failed (Status %lx)\n", Status);
2213 return Status;
2214 }
2215
2216 /* Get file attributes */
2217 Status = ZwQueryInformationFile(FileHandle,
2218 &IoStatusBlock,
2219 FileInformation,
2220 sizeof(FILE_NETWORK_OPEN_INFORMATION),
2221 FileNetworkOpenInformation);
2222 if (!NT_SUCCESS (Status))
2223 {
2224 DPRINT ("ZwQueryInformationFile() failed (Status %lx)\n", Status);
2225 }
2226
2227 ZwClose (FileHandle);
2228 return Status;
2229 }
2230
2231 /*
2232 * @implemented
2233 */
2234 NTSTATUS STDCALL
2235 NtQueryInformationFile(HANDLE FileHandle,
2236 PIO_STATUS_BLOCK IoStatusBlock,
2237 PVOID FileInformation,
2238 ULONG Length,
2239 FILE_INFORMATION_CLASS FileInformationClass)
2240 {
2241 OBJECT_HANDLE_INFORMATION HandleInformation;
2242 PFILE_OBJECT FileObject;
2243 NTSTATUS Status;
2244 PIRP Irp;
2245 PDEVICE_OBJECT DeviceObject;
2246 PIO_STACK_LOCATION StackPtr;
2247 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2248 KEVENT Event;
2249 BOOLEAN LocalEvent = FALSE;
2250 BOOLEAN Failed = FALSE;
2251
2252 ASSERT(IoStatusBlock != NULL);
2253 ASSERT(FileInformation != NULL);
2254
2255 DPRINT("NtQueryInformationFile(Handle %x StatBlk %x FileInfo %x Length %d "
2256 "Class %d)\n", FileHandle, IoStatusBlock, FileInformation,
2257 Length, FileInformationClass);
2258
2259 /* Reference the Handle */
2260 Status = ObReferenceObjectByHandle(FileHandle,
2261 0,
2262 IoFileObjectType,
2263 PreviousMode,
2264 (PVOID *)&FileObject,
2265 &HandleInformation);
2266 if (!NT_SUCCESS(Status)) return Status;
2267
2268 /* Check information class specific access rights */
2269 switch (FileInformationClass)
2270 {
2271 case FileBasicInformation:
2272 if (!(HandleInformation.GrantedAccess & FILE_READ_ATTRIBUTES))
2273 Failed = TRUE;
2274 break;
2275
2276 case FilePositionInformation:
2277 if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) ||
2278 !(FileObject->Flags & FO_SYNCHRONOUS_IO))
2279 Failed = TRUE;
2280 break;
2281
2282 case FileAlignmentInformation:
2283 if (!(FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING))
2284 Failed = TRUE;
2285 break;
2286
2287 default:
2288 break;
2289 }
2290
2291 if (Failed)
2292 {
2293 DPRINT1("NtQueryInformationFile() returns STATUS_ACCESS_DENIED!\n");
2294 ObDereferenceObject(FileObject);
2295 return STATUS_ACCESS_DENIED;
2296 }
2297
2298 DPRINT("FileObject %x\n", FileObject);
2299
2300 /* Check if this is a direct open or not */
2301 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2302 {
2303 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2304 }
2305 else
2306 {
2307 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2308 }
2309
2310 /* Check if we should use Sync IO or not */
2311 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2312 {
2313 /* Use File Object event */
2314 KeClearEvent(&FileObject->Event);
2315 }
2316 else
2317 {
2318 /* Use local event */
2319 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2320 LocalEvent = TRUE;
2321 }
2322
2323 /* Allocate the IRP */
2324 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE)))
2325 {
2326 ObDereferenceObject(FileObject);
2327 return STATUS_INSUFFICIENT_RESOURCES;
2328 }
2329
2330 /* Allocate the System Buffer */
2331 if (!(Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2332 Length,
2333 TAG_SYSB)))
2334 {
2335 IoFreeIrp(Irp);
2336 ObDereferenceObject(FileObject);
2337 return STATUS_INSUFFICIENT_RESOURCES;
2338 }
2339
2340 /* Set up the IRP */
2341 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2342 Irp->RequestorMode = PreviousMode;
2343 Irp->UserIosb = IoStatusBlock;
2344 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
2345 Irp->UserBuffer = FileInformation;
2346 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2347 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
2348 Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2349
2350 /* Set up Stack Data */
2351 StackPtr = IoGetNextIrpStackLocation(Irp);
2352 StackPtr->MajorFunction = IRP_MJ_QUERY_INFORMATION;
2353 StackPtr->FileObject = FileObject;
2354
2355 /* Set the Parameters */
2356 StackPtr->Parameters.QueryFile.FileInformationClass = FileInformationClass;
2357 StackPtr->Parameters.QueryFile.Length = Length;
2358
2359 /* Call the Driver */
2360 Status = IoCallDriver(DeviceObject, Irp);
2361 if (Status == STATUS_PENDING)
2362 {
2363 if (LocalEvent)
2364 {
2365 KeWaitForSingleObject(&Event,
2366 Executive,
2367 PreviousMode,
2368 FileObject->Flags & FO_ALERTABLE_IO,
2369 NULL);
2370 Status = IoStatusBlock->Status;
2371 }
2372 else
2373 {
2374 KeWaitForSingleObject(&FileObject->Event,
2375 Executive,
2376 PreviousMode,
2377 FileObject->Flags & FO_ALERTABLE_IO,
2378 NULL);
2379 Status = FileObject->FinalStatus;
2380 }
2381 }
2382
2383 /* Return the Status */
2384 return Status;
2385 }
2386
2387 /*
2388 * @unimplemented
2389 */
2390 NTSTATUS
2391 STDCALL
2392 NtQueryQuotaInformationFile(IN HANDLE FileHandle,
2393 OUT PIO_STATUS_BLOCK IoStatusBlock,
2394 OUT PVOID Buffer,
2395 IN ULONG Length,
2396 IN BOOLEAN ReturnSingleEntry,
2397 IN PVOID SidList OPTIONAL,
2398 IN ULONG SidListLength,
2399 IN PSID StartSid OPTIONAL,
2400 IN BOOLEAN RestartScan)
2401 {
2402 UNIMPLEMENTED;
2403 return STATUS_NOT_IMPLEMENTED;
2404 }
2405
2406 /*
2407 * NAME EXPORTED
2408 * NtReadFile
2409 *
2410 * DESCRIPTION
2411 *
2412 * ARGUMENTS
2413 *
2414 * RETURN VALUE
2415 *
2416 * REVISIONS
2417 *
2418 * @implemented
2419 */
2420 NTSTATUS
2421 STDCALL
2422 NtReadFile(IN HANDLE FileHandle,
2423 IN HANDLE Event OPTIONAL,
2424 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2425 IN PVOID ApcContext OPTIONAL,
2426 OUT PIO_STATUS_BLOCK IoStatusBlock,
2427 OUT PVOID Buffer,
2428 IN ULONG Length,
2429 IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
2430 IN PULONG Key OPTIONAL)
2431 {
2432 NTSTATUS Status = STATUS_SUCCESS;
2433 PFILE_OBJECT FileObject;
2434 PIRP Irp = NULL;
2435 PDEVICE_OBJECT DeviceObject;
2436 PIO_STACK_LOCATION StackPtr;
2437 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2438 BOOLEAN LocalEvent = FALSE;
2439 PKEVENT EventObject = NULL;
2440
2441 DPRINT("NtReadFile(FileHandle %x Buffer %x Length %x ByteOffset %x, "
2442 "IoStatusBlock %x)\n", FileHandle, Buffer, Length, ByteOffset,
2443 IoStatusBlock);
2444 PAGED_CODE();
2445
2446 /* Validate User-Mode Buffers */
2447 if(PreviousMode != KernelMode)
2448 {
2449 _SEH_TRY
2450 {
2451 ProbeForWrite(IoStatusBlock,
2452 sizeof(IO_STATUS_BLOCK),
2453 sizeof(ULONG));
2454 #if 0
2455 ProbeForWrite(Buffer,
2456 Length,
2457 sizeof(ULONG));
2458 #endif
2459 }
2460 _SEH_HANDLE
2461 {
2462 Status = _SEH_GetExceptionCode();
2463 }
2464 _SEH_END;
2465
2466 if(!NT_SUCCESS(Status)) return Status;
2467 }
2468
2469 /* Get File Object */
2470 Status = ObReferenceObjectByHandle(FileHandle,
2471 FILE_READ_DATA,
2472 IoFileObjectType,
2473 PreviousMode,
2474 (PVOID*)&FileObject,
2475 NULL);
2476 if (!NT_SUCCESS(Status)) return Status;
2477
2478 /* Check the Byte Offset */
2479 if (!ByteOffset ||
2480 (ByteOffset->u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
2481 ByteOffset->u.HighPart == 0xffffffff))
2482 {
2483 /* a valid ByteOffset is required if asynch. op. */
2484 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
2485 {
2486 DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n");
2487 ObDereferenceObject(FileObject);
2488 return STATUS_INVALID_PARAMETER;
2489 }
2490
2491 /* Use the Current Byte OFfset */
2492 ByteOffset = &FileObject->CurrentByteOffset;
2493 }
2494
2495 /* Check for event */
2496 if (Event)
2497 {
2498 /* Reference it */
2499 Status = ObReferenceObjectByHandle(Event,
2500 EVENT_MODIFY_STATE,
2501 ExEventObjectType,
2502 PreviousMode,
2503 (PVOID*)&EventObject,
2504 NULL);
2505 if (!NT_SUCCESS(Status))
2506 {
2507 ObDereferenceObject(FileObject);
2508 return Status;
2509 }
2510 KeClearEvent(EventObject);
2511 }
2512
2513 /* Check if this is a direct open or not */
2514 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2515 {
2516 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2517 }
2518 else
2519 {
2520 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2521 }
2522
2523 /* Check if we should use Sync IO or not */
2524 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2525 {
2526 /* Use File Object event */
2527 KeClearEvent(&FileObject->Event);
2528 }
2529 else
2530 {
2531 LocalEvent = TRUE;
2532 }
2533
2534 /* Create the IRP */
2535 _SEH_TRY
2536 {
2537 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2538 DeviceObject,
2539 Buffer,
2540 Length,
2541 ByteOffset,
2542 EventObject,
2543 IoStatusBlock);
2544 if (Irp == NULL)
2545 {
2546 Status = STATUS_INSUFFICIENT_RESOURCES;
2547 }
2548 }
2549 _SEH_HANDLE
2550 {
2551 Status = _SEH_GetExceptionCode();
2552 }
2553 _SEH_END;
2554
2555 /* Cleanup if IRP Allocation Failed */
2556 if (!NT_SUCCESS(Status))
2557 {
2558 if (Event) ObDereferenceObject(EventObject);
2559 ObDereferenceObject(FileObject);
2560 return Status;
2561 }
2562
2563 /* Set up IRP Data */
2564 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2565 Irp->RequestorMode = PreviousMode;
2566 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
2567 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
2568 Irp->Flags |= IRP_READ_OPERATION;
2569 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
2570
2571 /* Setup Stack Data */
2572 StackPtr = IoGetNextIrpStackLocation(Irp);
2573 StackPtr->FileObject = FileObject;
2574 StackPtr->Parameters.Read.Key = Key ? *Key : 0;
2575
2576 /* Call the Driver */
2577 Status = IoCallDriver(DeviceObject, Irp);
2578 if (Status == STATUS_PENDING)
2579 {
2580 if (!LocalEvent)
2581 {
2582 KeWaitForSingleObject(&FileObject->Event,
2583 Executive,
2584 PreviousMode,
2585 FileObject->Flags & FO_ALERTABLE_IO,
2586 NULL);
2587 Status = FileObject->FinalStatus;
2588 }
2589 }
2590
2591 /* Return the Status */
2592 return Status;
2593 }
2594
2595 /*
2596 * NAME EXPORTED
2597 * NtReadFileScatter
2598 *
2599 * DESCRIPTION
2600 *
2601 * ARGUMENTS
2602 *
2603 * RETURN VALUE
2604 *
2605 * REVISIONS
2606 */
2607 NTSTATUS
2608 STDCALL
2609 NtReadFileScatter(IN HANDLE FileHandle,
2610 IN HANDLE Event OPTIONAL,
2611 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
2612 IN PVOID UserApcContext OPTIONAL,
2613 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
2614 IN FILE_SEGMENT_ELEMENT BufferDescription [],
2615 IN ULONG BufferLength,
2616 IN PLARGE_INTEGER ByteOffset,
2617 IN PULONG Key OPTIONAL)
2618 {
2619 UNIMPLEMENTED;
2620 return(STATUS_NOT_IMPLEMENTED);
2621 }
2622
2623 /*
2624 * @unimplemented
2625 */
2626 NTSTATUS
2627 STDCALL
2628 NtSetEaFile(IN HANDLE FileHandle,
2629 IN PIO_STATUS_BLOCK IoStatusBlock,
2630 IN PVOID EaBuffer,
2631 IN ULONG EaBufferSize)
2632 {
2633 UNIMPLEMENTED;
2634 return STATUS_NOT_IMPLEMENTED;
2635 }
2636
2637 /*
2638 * @implemented
2639 */
2640 NTSTATUS STDCALL
2641 NtSetInformationFile(HANDLE FileHandle,
2642 PIO_STATUS_BLOCK IoStatusBlock,
2643 PVOID FileInformation,
2644 ULONG Length,
2645 FILE_INFORMATION_CLASS FileInformationClass)
2646 {
2647 OBJECT_HANDLE_INFORMATION HandleInformation;
2648 PIO_STACK_LOCATION StackPtr;
2649 PFILE_OBJECT FileObject;
2650 PDEVICE_OBJECT DeviceObject;
2651 PIRP Irp;
2652 KEVENT Event;
2653 BOOLEAN LocalEvent = FALSE;
2654 NTSTATUS Status = STATUS_SUCCESS;
2655 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2656 BOOLEAN Failed = FALSE;
2657
2658 ASSERT(IoStatusBlock != NULL);
2659 ASSERT(FileInformation != NULL);
2660
2661 DPRINT("NtSetInformationFile(Handle %x StatBlk %x FileInfo %x Length %d "
2662 "Class %d)\n", FileHandle, IoStatusBlock, FileInformation,
2663 Length, FileInformationClass);
2664
2665 /* Get the file object from the file handle */
2666 Status = ObReferenceObjectByHandle(FileHandle,
2667 0,
2668 IoFileObjectType,
2669 PreviousMode,
2670 (PVOID *)&FileObject,
2671 &HandleInformation);
2672 if (!NT_SUCCESS(Status)) return Status;
2673
2674 /* Check information class specific access rights */
2675 switch (FileInformationClass)
2676 {
2677 case FileBasicInformation:
2678 if (!(HandleInformation.GrantedAccess & FILE_WRITE_ATTRIBUTES))
2679 Failed = TRUE;
2680 break;
2681
2682 case FileDispositionInformation:
2683 if (!(HandleInformation.GrantedAccess & DELETE))
2684 Failed = TRUE;
2685 break;
2686
2687 case FilePositionInformation:
2688 if (!(HandleInformation.GrantedAccess & (FILE_READ_DATA | FILE_WRITE_DATA)) ||
2689 !(FileObject->Flags & FO_SYNCHRONOUS_IO))
2690 Failed = TRUE;
2691 break;
2692
2693 case FileEndOfFileInformation:
2694 if (!(HandleInformation.GrantedAccess & FILE_WRITE_DATA))
2695 Failed = TRUE;
2696 break;
2697
2698 default:
2699 break;
2700 }
2701
2702 if (Failed)
2703 {
2704 DPRINT1("NtSetInformationFile() returns STATUS_ACCESS_DENIED!\n");
2705 ObDereferenceObject(FileObject);
2706 return STATUS_ACCESS_DENIED;
2707 }
2708
2709 DPRINT("FileObject %x\n", FileObject);
2710
2711 /* FIXME: Later, we can implement a lot of stuff here and avoid a driver call */
2712 /* Handle IO Completion Port quickly */
2713 if (FileInformationClass == FileCompletionInformation)
2714 {
2715 PVOID Queue;
2716 PFILE_COMPLETION_INFORMATION CompletionInfo = FileInformation;
2717 PIO_COMPLETION_CONTEXT Context;
2718
2719 if (Length < sizeof(FILE_COMPLETION_INFORMATION))
2720 {
2721 Status = STATUS_INFO_LENGTH_MISMATCH;
2722 }
2723 else
2724 {
2725 /* Reference the Port */
2726 Status = ObReferenceObjectByHandle(CompletionInfo->IoCompletionHandle,
2727 IO_COMPLETION_MODIFY_STATE,
2728 ExIoCompletionType,
2729 PreviousMode,
2730 (PVOID*)&Queue,
2731 NULL);
2732 if (NT_SUCCESS(Status))
2733 {
2734 /* Allocate the Context */
2735 Context = ExAllocatePoolWithTag(PagedPool,
2736 sizeof(IO_COMPLETION_CONTEXT),
2737 TAG('I', 'o', 'C', 'p'));
2738
2739 /* Set the Data */
2740 Context->Key = CompletionInfo->CompletionKey;
2741 Context->Port = Queue;
2742 FileObject->CompletionContext = Context;
2743
2744 /* Dereference the Port now */
2745 ObDereferenceObject(Queue);
2746 }
2747 }
2748
2749 /* Complete the I/O */
2750 ObDereferenceObject(FileObject);
2751 return Status;
2752 }
2753
2754 /* Check if this is a direct open or not */
2755 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
2756 {
2757 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
2758 }
2759 else
2760 {
2761 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2762 }
2763
2764 /* Check if we should use Sync IO or not */
2765 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
2766 {
2767 /* Use File Object event */
2768 KeClearEvent(&FileObject->Event);
2769 }
2770 else
2771 {
2772 /* Use local event */
2773 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
2774 LocalEvent = TRUE;
2775 }
2776
2777 /* Allocate the IRP */
2778 if (!(Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE)))
2779 {
2780 ObDereferenceObject(FileObject);
2781 return STATUS_INSUFFICIENT_RESOURCES;
2782 }
2783
2784 /* Allocate the System Buffer */
2785 if (!(Irp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithTag(NonPagedPool,
2786 Length,
2787 TAG_SYSB)))
2788 {
2789 IoFreeIrp(Irp);
2790 ObDereferenceObject(FileObject);
2791 return STATUS_INSUFFICIENT_RESOURCES;
2792 }
2793
2794 /* Copy the data inside */
2795 MmSafeCopyFromUser(Irp->AssociatedIrp.SystemBuffer, FileInformation, Length);
2796
2797 /* Set up the IRP */
2798 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2799 Irp->RequestorMode = PreviousMode;
2800 Irp->UserIosb = IoStatusBlock;
2801 Irp->UserEvent = (LocalEvent) ? &Event : NULL;
2802 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2803 Irp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
2804 Irp->Flags |= (LocalEvent) ? IRP_SYNCHRONOUS_API : 0;
2805
2806 /* Set up Stack Data */
2807 StackPtr = IoGetNextIrpStackLocation(Irp);
2808 StackPtr->MajorFunction = IRP_MJ_SET_INFORMATION;
2809 StackPtr->FileObject = FileObject;
2810
2811 /* Set the Parameters */
2812 StackPtr->Parameters.SetFile.FileInformationClass = FileInformationClass;
2813 StackPtr->Parameters.SetFile.Length = Length;
2814
2815 /* Call the Driver */
2816 Status = IoCallDriver(DeviceObject, Irp);
2817 if (Status == STATUS_PENDING)
2818 {
2819 if (LocalEvent)
2820 {
2821 KeWaitForSingleObject(&Event,
2822 Executive,
2823 PreviousMode,
2824 FileObject->Flags & FO_ALERTABLE_IO,
2825 NULL);
2826 Status = IoStatusBlock->Status;
2827 }
2828 else
2829 {
2830 KeWaitForSingleObject(&FileObject->Event,
2831 Executive,
2832 PreviousMode,
2833 FileObject->Flags & FO_ALERTABLE_IO,
2834 NULL);
2835 Status = FileObject->FinalStatus;
2836 }
2837 }
2838
2839 /* Return the Status */
2840 return Status;
2841 }
2842
2843 /*
2844 * @unimplemented
2845 */
2846 NTSTATUS
2847 STDCALL
2848 NtSetQuotaInformationFile(HANDLE FileHandle,
2849 PIO_STATUS_BLOCK IoStatusBlock,
2850 PFILE_USER_QUOTA_INFORMATION Buffer,
2851 ULONG BufferLength)
2852 {
2853 UNIMPLEMENTED;
2854 return STATUS_NOT_IMPLEMENTED;
2855 }
2856
2857 /*
2858 * @unimplemented
2859 */
2860 NTSTATUS
2861 STDCALL
2862 NtUnlockFile(IN HANDLE FileHandle,
2863 OUT PIO_STATUS_BLOCK IoStatusBlock,
2864 IN PLARGE_INTEGER ByteOffset,
2865 IN PLARGE_INTEGER Length,
2866 OUT PULONG Key OPTIONAL)
2867 {
2868 PFILE_OBJECT FileObject = NULL;
2869 PLARGE_INTEGER LocalLength = NULL;
2870 PIRP Irp = NULL;
2871 PIO_STACK_LOCATION StackPtr;
2872 PDEVICE_OBJECT DeviceObject;
2873 KPROCESSOR_MODE PreviousMode;
2874 NTSTATUS Status;
2875
2876 // FIXME: instead of this, use SEH when available
2877 if (!Length || !ByteOffset)
2878 {
2879 Status = STATUS_INVALID_PARAMETER;
2880 goto fail;
2881 }
2882
2883 PreviousMode = ExGetPreviousMode();
2884
2885 /*
2886 * BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
2887 * It should ONLY fail if we desire an access that conflict with granted access!
2888 */
2889 Status = ObReferenceObjectByHandle(FileHandle,
2890 0, //FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
2891 IoFileObjectType,
2892 PreviousMode,
2893 (PVOID*)&FileObject,
2894 NULL);
2895 if (!NT_SUCCESS(Status))
2896 {
2897 goto fail;
2898 }
2899
2900 DeviceObject = IoGetRelatedDeviceObject(FileObject);
2901
2902 Irp = IoAllocateIrp(DeviceObject->StackSize,
2903 TRUE);
2904 if (Irp == NULL)
2905 {
2906 Status = STATUS_INSUFFICIENT_RESOURCES;
2907 goto fail;
2908 }
2909
2910 /* Trigger FileObject/Event dereferencing */
2911 Irp->Tail.Overlay.OriginalFileObject = FileObject;
2912 Irp->RequestorMode = PreviousMode;
2913 Irp->UserIosb = IoStatusBlock;
2914 Irp->Tail.Overlay.Thread = PsGetCurrentThread();
2915
2916 StackPtr = IoGetNextIrpStackLocation(Irp);
2917 StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
2918 StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
2919 StackPtr->DeviceObject = DeviceObject;
2920 StackPtr->FileObject = FileObject;
2921
2922 LocalLength = ExAllocatePoolWithTag(NonPagedPool,
2923 sizeof(LARGE_INTEGER),
2924 TAG_LOCK);
2925 if (!LocalLength)
2926 {
2927 Status = STATUS_INSUFFICIENT_RESOURCES;
2928 goto fail;
2929 }
2930
2931 *LocalLength = *Length;
2932
2933 StackPtr->Parameters.LockControl.Length = LocalLength;
2934 StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
2935 StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
2936
2937 /* Allways synchronous */
2938 Status = IofCallDriver(DeviceObject, Irp);
2939
2940 ExFreePool(LocalLength);
2941
2942 return Status;
2943
2944 fail:;
2945 if (LocalLength)
2946 ExFreePool(LocalLength);
2947
2948 if (Irp)
2949 IoFreeIrp(Irp);
2950
2951 if (FileObject)
2952 ObDereferenceObject(FileObject);
2953
2954 return Status;
2955 }
2956
2957 /*
2958 * NAME EXPORTED
2959 * NtWriteFile
2960 *
2961 * DESCRIPTION
2962 *
2963 * ARGUMENTS
2964 *
2965 * RETURN VALUE
2966 *
2967 * REVISIONS
2968 *
2969 * @implemented
2970 */
2971 NTSTATUS
2972 STDCALL
2973 NtWriteFile (IN HANDLE FileHandle,
2974 IN HANDLE Event OPTIONAL,
2975 IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
2976 IN PVOID ApcContext OPTIONAL,
2977 OUT PIO_STATUS_BLOCK IoStatusBlock,
2978 IN PVOID Buffer,
2979 IN ULONG Length,
2980 IN PLARGE_INTEGER ByteOffset OPTIONAL, /* NOT optional for asynch. operations! */
2981 IN PULONG Key OPTIONAL)
2982 {
2983 OBJECT_HANDLE_INFORMATION HandleInformation;
2984 NTSTATUS Status = STATUS_SUCCESS;
2985 PFILE_OBJECT FileObject;
2986 PIRP Irp = NULL;
2987 PDEVICE_OBJECT DeviceObject;
2988 PIO_STACK_LOCATION StackPtr;
2989 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
2990 BOOLEAN LocalEvent = FALSE;
2991 PKEVENT EventObject = NULL;
2992
2993 DPRINT("NtWriteFile(FileHandle %x Buffer %x Length %x ByteOffset %x, "
2994 "IoStatusBlock %x)\n", FileHandle, Buffer, Length, ByteOffset,
2995 IoStatusBlock);
2996
2997 /* Validate User-Mode Buffers */
2998 if(PreviousMode != KernelMode)
2999 {
3000 _SEH_TRY
3001 {
3002 #if 0
3003 ProbeForWrite(IoStatusBlock,
3004 sizeof(IO_STATUS_BLOCK),
3005 sizeof(ULONG));
3006
3007 ProbeForRead(Buffer,
3008 Length,
3009 sizeof(ULONG));
3010 #endif
3011 }
3012 _SEH_HANDLE
3013 {
3014 Status = _SEH_GetExceptionCode();
3015 }
3016 _SEH_END;
3017
3018 if(!NT_SUCCESS(Status)) return Status;
3019 }
3020
3021 /* Get File Object */
3022 Status = ObReferenceObjectByHandle(FileHandle,
3023 0,
3024 IoFileObjectType,
3025 PreviousMode,
3026 (PVOID*)&FileObject,
3027 &HandleInformation);
3028 if (!NT_SUCCESS(Status)) return Status;
3029
3030 /* Must have FILE_WRITE_DATA | FILE_APPEND_DATA access */
3031 if (!(HandleInformation.GrantedAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))
3032 {
3033 DPRINT1("Invalid access rights\n");
3034 ObDereferenceObject(FileObject);
3035 return STATUS_ACCESS_DENIED;
3036 }
3037
3038 /* Check if we got write Access */
3039 if (HandleInformation.GrantedAccess & FILE_WRITE_DATA)
3040 {
3041 /* Check the Byte Offset */
3042 if (!ByteOffset ||
3043 (ByteOffset->u.LowPart == FILE_USE_FILE_POINTER_POSITION &&
3044 ByteOffset->u.HighPart == 0xffffffff))
3045 {
3046 /* a valid ByteOffset is required if asynch. op. */
3047 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
3048 {
3049 DPRINT1("NtReadFile: missing ByteOffset for asynch. op\n");
3050 ObDereferenceObject(FileObject);
3051 return STATUS_INVALID_PARAMETER;
3052 }
3053
3054 /* Use the Current Byte OFfset */
3055 ByteOffset = &FileObject->CurrentByteOffset;
3056 }
3057 }
3058 else if (HandleInformation.GrantedAccess & FILE_APPEND_DATA)
3059 {
3060 /* a valid ByteOffset is required if asynch. op. */
3061 if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
3062 {
3063 DPRINT1("NtWriteFile: missing ByteOffset for asynch. op\n");
3064 ObDereferenceObject(FileObject);
3065 return STATUS_INVALID_PARAMETER;
3066 }
3067
3068 /* Give the drivers somethign to understand */
3069 ByteOffset->u.LowPart = FILE_WRITE_TO_END_OF_FILE;
3070 ByteOffset->u.HighPart = 0xffffffff;
3071 }
3072
3073 /* Check if we got an event */
3074 if (Event)
3075 {
3076 /* Reference it */
3077 Status = ObReferenceObjectByHandle(Event,
3078 EVENT_MODIFY_STATE,
3079 ExEventObjectType,
3080 PreviousMode,
3081 (PVOID*)&EventObject,
3082 NULL);
3083 if (!NT_SUCCESS(Status))
3084 {
3085 ObDereferenceObject(FileObject);
3086 return Status;
3087 }
3088 KeClearEvent(EventObject);
3089 }
3090
3091 /* Check if this is a direct open or not */
3092 if (FileObject->Flags & FO_DIRECT_DEVICE_OPEN)
3093 {
3094 DeviceObject = IoGetAttachedDevice(FileObject->DeviceObject);
3095 }
3096 else
3097 {
3098 DeviceObject = IoGetRelatedDeviceObject(FileObject);
3099 }
3100
3101 /* Check if we should use Sync IO or not */
3102 if (FileObject->Flags & FO_SYNCHRONOUS_IO)
3103 {
3104 /* Use File Object event */
3105 KeClearEvent(&FileObject->Event);
3106 }
3107 else
3108 {
3109 LocalEvent = TRUE;
3110 }
3111
3112 /* Build the IRP */
3113 _SEH_TRY
3114 {
3115 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
3116 FileObject->DeviceObject,
3117 Buffer,
3118 Length,
3119 ByteOffset,
3120 EventObject,
3121 IoStatusBlock);
3122 if (Irp == NULL)
3123 {
3124 Status = STATUS_INSUFFICIENT_RESOURCES;
3125 }
3126 }
3127 _SEH_HANDLE
3128 {
3129 Status = _SEH_GetExceptionCode();
3130 }
3131 _SEH_END;
3132
3133 /* Cleanup on failure */
3134 if (!NT_SUCCESS(Status))
3135 {
3136 if (Event)
3137 {
3138 ObDereferenceObject(&EventObject);
3139 }
3140 ObDereferenceObject(FileObject);
3141 return Status;
3142 }
3143
3144 /* Set up IRP Data */
3145 Irp->Tail.Overlay.OriginalFileObject = FileObject;
3146 Irp->RequestorMode = PreviousMode;
3147 Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
3148 Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
3149 Irp->Flags |= IRP_WRITE_OPERATION;
3150 if (FileObject->Flags & FO_NO_INTERMEDIATE_BUFFERING) Irp->Flags |= IRP_NOCACHE;
3151
3152 /* Setup Stack Data */
3153 StackPtr = IoGetNextIrpStackLocation(Irp);
3154 StackPtr->FileObject = FileObject;
3155 StackPtr->Parameters.Write.Key = Key ? *Key : 0;
3156 if (FileObject->Flags & FO_WRITE_THROUGH) StackPtr->Flags = SL_WRITE_THROUGH;
3157
3158 /* Call the Driver */
3159 Status = IoCallDriver(DeviceObject, Irp);
3160 if (Status == STATUS_PENDING)
3161 {
3162 if (!LocalEvent)
3163 {
3164 KeWaitForSingleObject(&FileObject->Event,
3165 Executive,
3166 PreviousMode,
3167 FileObject->Flags & FO_ALERTABLE_IO,
3168 NULL);
3169 Status = FileObject->FinalStatus;
3170 }
3171 }
3172
3173 /* Return the Status */
3174 return Status;
3175 }
3176
3177 /*
3178 * NAME EXPORTED
3179 * NtWriteFileGather
3180 *
3181 * DESCRIPTION
3182 *
3183 * ARGUMENTS
3184 *
3185 * RETURN VALUE
3186 *
3187 * REVISIONS
3188 */
3189 NTSTATUS
3190 STDCALL
3191 NtWriteFileGather(IN HANDLE FileHandle,
3192 IN HANDLE Event OPTIONAL,
3193 IN PIO_APC_ROUTINE UserApcRoutine OPTIONAL,
3194 IN PVOID UserApcContext OPTIONAL,
3195 OUT PIO_STATUS_BLOCK UserIoStatusBlock,
3196 IN FILE_SEGMENT_ELEMENT BufferDescription [],
3197 IN ULONG BufferLength,
3198 IN PLARGE_INTEGER ByteOffset,
3199 IN PULONG Key OPTIONAL)
3200 {
3201 UNIMPLEMENTED;
3202 return(STATUS_NOT_IMPLEMENTED);
3203 }
3204 /* EOF */