test: vdm.c Source File

Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

# vdm.c

Go to the documentation of this file.

    00001 /*++
    00002
    00003 Copyright (c) 1991  Microsoft Corporation
    00004
    00005 Module Name:
    00006
    00007     vdm.c
    00008
    00009 Abstract:
    00010
    00011     This module supplies the entry point to the system for manipulating vdms.
    00012
    00013 Author:
    00014
    00015     Dave Hastings (daveh) 6-Apr-1992
    00016
    00017 Revision History:
    00018
    00019 --*/
    00020
    00021
    00022 #include <ntos.h>
    00023 #include <vdmntos.h>
    00024 #include <ntvdmp.h>
    00025
    00026 #include <zwapi.h>
    00027 #include <fsrtl.h>
    00028
    00029
    00030 typedef struct _QueryDirPoolData {
    00031     KEVENT         kevent;
    00032     UNICODE_STRING FileName;
    00033     WCHAR          FileNameBuf[1];
    00034 } QDIR_POOLDATA, *PQDIR_POOLDATA;
    00035
    00036
    00037
    00038 #ifdef ALLOC_PRAGMA
    00039 #pragma alloc_text(PAGE, VdmQueryDirectoryFile)
    00040 #endif
    00041
    00042 #if !defined(i386)
    00043
    00044 #ifdef ALLOC_PRAGMA
    00045 #pragma alloc_text(PAGE, NtVdmControl)
    00046 #endif
    00047
    00048 NTSTATUS
    00049 NtVdmControl(
    00050     IN VDMSERVICECLASS Service,
    00051     IN OUT PVOID ServiceData
    00052     )
    00053 /*++
    00054
    00055 Routine Description:
    00056
    00057     This routine is the entry point for controlling Vdms.
    00058     On risc it returns STATUS_NOT_IMPLEMENTED.
    00059     On 386 the entry point is in i386\vdmentry.c
    00060
    00061 Arguments:
    00062
    00063     Service -- Specifies what service is to be performed
    00064     ServiceData -- Supplies a pointer to service specific data
    00065
    00066 Return Value:
    00067
    00068
    00069 --*/
    00070 {
    00071     PAGED_CODE();
    00072
    00073
    00074     if (Service == VdmQueryDir) {
    00075         return VdmQueryDirectoryFile(ServiceData);
    00076         }
    00077
    00078     return STATUS_NOT_IMPLEMENTED;
    00079
    00080 }
    00081 #endif
    00082
    00083
    00084 extern POBJECT_TYPE IoFileObjectType;
    00085
    00086 NTSTATUS
    00087 VdmQueryDirectoryFile(
    00088     PVDMQUERYDIRINFO pVdmQueryDir
    00089     )
    00090
    00091 /*++
    00092     This VDM specific service allows vdm to restart searches at a specified
    00093     location in the dir search by using the FileIndex, FileName parameters
    00094     passed back from previous query calls.
    00095
    00096     See NtQueryDirectoryFile for additional documentation.
    00097
    00098 Arguments: PVDMQUERYDIRINFO pVdmQueryDir
    00099
    00100     FileHandle - Supplies a handle to the directory file for which information
    00101         should be returned.
    00102
    00103     FileInformation - Supplies a buffer to receive the requested information
    00104         returned about the contents of the directory.
    00105
    00106     Length - Supplies the length, in bytes, of the FileInformation buffer.
    00107
    00108     FileName - Supplies a file name within the specified directory.
    00109
    00110     FileIndex - Supplies a file index within the specified directory.
    00111
    00112     The FileInformationClass is assumed to be FILE_BOTH_DIR_INFORMATION
    00113     The Caller's mode is assumed to be UserMode
    00114     Synchronous IO is used
    00115
    00116 --*/
    00117
    00118 {
    00119     KIRQL    irql;
    00120     NTSTATUS status;
    00121     PKEVENT  Event;
    00122
    00123     HANDLE FileHandle;
    00124     IO_STATUS_BLOCK IoStatusBlock;
    00125     PVOID FileInformation;
    00126     ULONG Length;
    00127     UNICODE_STRING FileName;
    00128     PUNICODE_STRING pFileNameSrc;
    00129     ULONG FileIndex;
    00130
    00131     PQDIR_POOLDATA QDirPoolData = NULL;
    00132     FILE_FS_DEVICE_INFORMATION DeviceInfo;
    00133
    00134     PMDL mdl;
    00135     PIRP irp;
    00136     PIO_STACK_LOCATION irpSp;
    00137     PCHAR SystemBuffer;
    00138     PFILE_OBJECT fileObject;
    00139     PDEVICE_OBJECT DeviceObject;
    00140
    00141
    00142     PAGED_CODE();
    00143
    00144     //
    00145     // We assume that the caller is usermode, so verify all parameters
    00146     // accordingly
    00147     //
    00148
    00149     try {
    00150
    00151         //
    00152         // Copy out the callers service data into local variables
    00153         //
    00154         ProbeForRead( pVdmQueryDir, sizeof(VDMQUERYDIRINFO), sizeof(ULONG));
    00155
    00156         FileHandle      = pVdmQueryDir->FileHandle;
    00157         FileInformation = pVdmQueryDir->FileInformation;
    00158         Length          = pVdmQueryDir->Length;
    00159         FileIndex       = pVdmQueryDir->FileIndex;
    00160         pFileNameSrc    = pVdmQueryDir->FileName;
    00161
    00162         //
    00163         // Ensure that we have a valid file name string
    00164         //
    00165
    00166         //
    00167         // check for pVdmQueryDir->Filename validity first
    00168         //
    00169         if (NULL == pFileNameSrc) {
    00170            return(STATUS_INVALID_PARAMETER);
    00171         }
    00172
    00173         FileName = ProbeAndReadUnicodeString(pFileNameSrc);
    00174         if (!FileName.Length ||
    00175             FileName.Length > MAXIMUM_FILENAME_LENGTH<<1) {
    00176             return(STATUS_INVALID_PARAMETER);
    00177         }
    00178
    00179         ProbeForRead(FileName.Buffer, FileName.Length, sizeof( UCHAR ));
    00180
    00181         //
    00182         // The FileInformation buffer must be writeable by the caller.
    00183         //
    00184
    00185         ProbeForWrite( FileInformation, Length, sizeof( ULONG ) );
    00186
    00187         //
    00188         // Ensure that the caller's supplied buffer is at least large enough
    00189         // to contain the fixed part of the structure required for this
    00190         // query.
    00191         //
    00192
    00193         if (Length < sizeof(FILE_BOTH_DIR_INFORMATION)) {
    00194             return STATUS_INFO_LENGTH_MISMATCH;
    00195         }
    00196
    00197
    00198
    00199         //
    00200         // Allocate from nonpaged pool a buffer large enough to contain
    00201         // the file name, and the kevent used to wait for io.
    00202         //
    00203
    00204         QDirPoolData = (PQDIR_POOLDATA) ExAllocatePoolWithQuotaTag(
    00205                                            NonPagedPool,
    00206                                            sizeof(QDIR_POOLDATA) + FileName.Length,
    00207                                            ' MDV');
    00208
    00209         //
    00210         // Capture the file name string into the nonpaged pool block.
    00211         //
    00212
    00213         QDirPoolData->FileName.Length = FileName.Length;
    00214         QDirPoolData->FileName.MaximumLength = FileName.Length;
    00215         QDirPoolData->FileName.Buffer = QDirPoolData->FileNameBuf;
    00216         RtlCopyMemory( QDirPoolData->FileNameBuf,
    00217                        FileName.Buffer,
    00218                        FileName.Length );
    00219
    00220
    00221     } except(EXCEPTION_EXECUTE_HANDLER) {
    00222
    00223         if (QDirPoolData) {
    00224             ExFreePool(QDirPoolData);
    00225         }
    00226
    00227         return GetExceptionCode();
    00228     }
    00229
    00230     //
    00231     // There were no blatant errors so far, so reference the file object so
    00232     // the target device object can be found.  Note that if the handle does
    00233     // not refer to a file object, or if the caller does not have the required
    00234     // access to the file, then it will fail.
    00235     //
    00236
    00237     status = ObReferenceObjectByHandle( FileHandle,
    00238                                         FILE_LIST_DIRECTORY,
    00239                                         IoFileObjectType,
    00240                                         UserMode,
    00241                                         (PVOID *) &fileObject,
    00242                                         (POBJECT_HANDLE_INFORMATION) NULL );
    00243     if (!NT_SUCCESS( status )) {
    00244         if (QDirPoolData) {
    00245             ExFreePool(QDirPoolData);
    00246         }
    00247         return status;
    00248     }
    00249
    00250     //
    00251     //  We don't handle FO_SYNCHRONOUS_IO, because it requires
    00252     //  io internal finctionality. Ntvdm can get away with this
    00253     //  because it serializes access to the dir handle.
    00254     //
    00255
    00256     //
    00257     // Initialize the kernel event that will signal I/O completion
    00258     //
    00259     Event = &QDirPoolData->kevent;
    00260     KeInitializeEvent(Event, SynchronizationEvent, FALSE);
    00261
    00262
    00263     //
    00264     // Set the file object to the Not-Signaled state.
    00265     //
    00266
    00267     KeClearEvent( &fileObject->Event );
    00268
    00269     //
    00270     // Get the address of the target device object.
    00271     //
    00272
    00273     DeviceObject = IoGetRelatedDeviceObject( fileObject );
    00274
    00275     //
    00276     // Allocate and initialize the I/O Request Packet (IRP) for this operation.
    00277     // The allocation is performed with an exception handler in case the
    00278     // caller does not have enough quota to allocate the packet.
    00279
    00280     irp = IoAllocateIrp( DeviceObject->StackSize, TRUE );
    00281     if (!irp) {
    00282
    00283         //
    00284         // An IRP could not be allocated.  Cleanup and return an appropriate
    00285         // error status code.
    00286         //
    00287
    00288         ObDereferenceObject( fileObject );
    00289         if (QDirPoolData) {
    00290             ExFreePool(QDirPoolData);
    00291         }
    00292
    00293         return STATUS_INSUFFICIENT_RESOURCES;
    00294     }
    00295
    00296     //
    00297     // Fill in the service independent parameters in the IRP.
    00298     //
    00299
    00300     irp->Flags = (ULONG)IRP_SYNCHRONOUS_API;
    00301     irp->RequestorMode = UserMode;
    00302
    00303     irp->UserIosb = &IoStatusBlock;
    00304     irp->UserEvent = Event;
    00305
    00306     irp->Overlay.AsynchronousParameters.UserApcRoutine = NULL;
    00307     irp->AssociatedIrp.SystemBuffer = (PVOID) NULL;
    00308     SystemBuffer = NULL;
    00309
    00310
    00311     irp->Tail.Overlay.Thread = PsGetCurrentThread();
    00312     irp->Tail.Overlay.OriginalFileObject = fileObject;
    00313     irp->Tail.Overlay.AuxiliaryBuffer = NULL;
    00314     irp->MdlAddress = NULL;
    00315
    00316     //
    00317     // Get a pointer to the stack location for the first driver.  This will be
    00318     // used to pass the function codes and parameters.
    00319     //
    00320
    00321     irpSp = IoGetNextIrpStackLocation( irp );
    00322     irpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
    00323     irpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
    00324     irpSp->FileObject = fileObject;
    00325
    00326
    00327     //
    00328     // Copy the caller's parameters to the service-specific portion of the
    00329     // IRP.
    00330     //
    00331
    00332     irpSp->Parameters.QueryDirectory.Length = Length;
    00333     irpSp->Parameters.QueryDirectory.FileInformationClass = FileBothDirectoryInformation;
    00334     irpSp->Parameters.QueryDirectory.FileIndex = FileIndex;
    00335
    00336     if (QDirPoolData->FileName.Length) {
    00337         irpSp->Parameters.QueryDirectory.FileName = (PSTRING)&QDirPoolData->FileName;
    00338     } else {
    00339         irpSp->Parameters.QueryDirectory.FileName = NULL;
    00340     }
    00341
    00342     irpSp->Flags = SL_INDEX_SPECIFIED;
    00343
    00344
    00345     //
    00346     // Now determine whether this driver expects to have data buffered to it
    00347     // or whether it performs direct I/O.  This is based on the DO_BUFFERED_IO
    00348     // flag in the device object.  If the flag is set, then a system buffer is
    00349     // allocated and the driver's data will be copied into it.  Otherwise, a
    00350     // Memory Descriptor List (MDL) is allocated and the caller's buffer is
    00351     // locked down using it.
    00352     //
    00353
    00354     if (DeviceObject->Flags & DO_BUFFERED_IO) {
    00355
    00356         //
    00357         // The file system wants buffered I/O.  Pass the address of the
    00358         // "system buffer" in the IRP.  Note that we don't want the buffer
    00359         // deallocated, nor do we want the I/O system to copy to a user
    00360         // buffer, so we don't set the corresponding flags in irp->Flags.
    00361         //
    00362
    00363
    00364         try {
    00365
    00366             //
    00367             // Allocate the intermediary system buffer from nonpaged pool and
    00368             // charge quota for it.
    00369             //
    00370
    00371             SystemBuffer = ExAllocatePoolWithQuotaTag( NonPagedPool,
    00372                                                        Length,
    00373                                                        ' MDV' );
    00374
    00375             irp->AssociatedIrp.SystemBuffer = SystemBuffer;
    00376
    00377
    00378         } except(EXCEPTION_EXECUTE_HANDLER) {
    00379
    00380             IoFreeIrp(irp);
    00381
    00382             ObDereferenceObject( fileObject );
    00383
    00384             if (QDirPoolData) {
    00385                 ExFreePool(QDirPoolData);
    00386             }
    00387
    00388             return GetExceptionCode();
    00389         }
    00390
    00391
    00392     } else if (DeviceObject->Flags & DO_DIRECT_IO) {
    00393
    00394         //
    00395         // This is a direct I/O operation.  Allocate an MDL and invoke the
    00396         // memory management routine to lock the buffer into memory.  This is
    00397         // done using an exception handler that will perform cleanup if the
    00398         // operation fails.
    00399         //
    00400
    00401         mdl = (PMDL) NULL;
    00402
    00403         try {
    00404
    00405             //
    00406             // Allocate an MDL, charging quota for it, and hang it off of the
    00407             // IRP.  Probe and lock the pages associated with the caller's
    00408             // buffer for write access and fill in the MDL with the PFNs of
    00409             // those pages.
    00410             //
    00411
    00412             mdl = IoAllocateMdl( FileInformation, Length, FALSE, TRUE, irp );
    00413             if (mdl == NULL) {
    00414                 ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
    00415             }
    00416             MmProbeAndLockPages( mdl, UserMode, IoWriteAccess );
    00417
    00418         } except(EXCEPTION_EXECUTE_HANDLER) {
    00419
    00420             if (irp->MdlAddress != NULL) {
    00421                  IoFreeMdl( irp->MdlAddress );
    00422             }
    00423
    00424             IoFreeIrp(irp);
    00425
    00426             ObDereferenceObject( fileObject );
    00427
    00428             if (QDirPoolData) {
    00429                 ExFreePool(QDirPoolData);
    00430             }
    00431
    00432             return GetExceptionCode();
    00433         }
    00434
    00435     } else {
    00436
    00437         //
    00438         // Pass the address of the user's buffer so the driver has access to
    00439         // it.  It is now the driver's responsibility to do everything.
    00440         //
    00441
    00442         irp->UserBuffer = FileInformation;
    00443
    00444     }
    00445
    00446
    00447     //
    00448     // Insert the packet at the head of the IRP list for the thread.
    00449     //
    00450
    00451     KeRaiseIrql( APC_LEVEL, &irql );
    00452     InsertHeadList( &irp->Tail.Overlay.Thread->IrpList,
    00453                     &irp->ThreadListEntry );
    00454     KeLowerIrql( irql );
    00455
    00456
    00457     //
    00458     // invoke the driver and wait for it to complete
    00459     //
    00460
    00461     status = IoCallDriver(DeviceObject, irp);
    00462
    00463     if (status == STATUS_PENDING) {
    00464         status = KeWaitForSingleObject(
    00465                      Event,
    00466                      UserRequest,
    00467                      UserMode,
    00468                      FALSE,
    00469                      NULL );
    00470     }
    00471
    00472     if (NT_SUCCESS(status)) {
    00473         status = IoStatusBlock.Status;
    00474         if (NT_SUCCESS(status) || status == STATUS_BUFFER_OVERFLOW) {
    00475             if (SystemBuffer) {
    00476                 try {
    00477                     RtlCopyMemory( FileInformation,
    00478                                    SystemBuffer,
    00479                                    IoStatusBlock.Information
    00480                                    );
    00481
    00482                 } except(EXCEPTION_EXECUTE_HANDLER) {
    00483                     status = GetExceptionCode();
    00484                 }
    00485             }
    00486         }
    00487     }
    00488
    00489
    00490     //
    00491     // Cleanup any memory allocated
    00492     //
    00493     if (QDirPoolData) {
    00494         ExFreePool(QDirPoolData);
    00495     }
    00496
    00497     if (SystemBuffer) {
    00498         ExFreePool(SystemBuffer);
    00499     }
    00500
    00501
    00502     return status;
    00503 }