ntoskrnl.exe: Implement volume information queries for device files.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
1b48335762
commit
a656ca5e32
|
@ -760,6 +760,55 @@ static NTSTATUS dispatch_ioctl( struct dispatch_context *context )
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* process a volume information request for a given device */
|
||||
static NTSTATUS dispatch_volume( struct dispatch_context *context )
|
||||
{
|
||||
IO_STACK_LOCATION *irpsp;
|
||||
IRP *irp;
|
||||
void *out_buff = NULL;
|
||||
DEVICE_OBJECT *device;
|
||||
FILE_OBJECT *file = wine_server_get_ptr( context->params.volume.file );
|
||||
ULONG out_size = context->params.volume.out_size;
|
||||
|
||||
if (!file) return STATUS_INVALID_HANDLE;
|
||||
|
||||
device = IoGetAttachedDevice( file->DeviceObject );
|
||||
|
||||
TRACE( "class 0x%x device %p file %p in_size %u out_size %u\n",
|
||||
context->params.volume.info_class, device, file, context->in_size, out_size );
|
||||
|
||||
if (!(out_buff = HeapAlloc( GetProcessHeap(), 0, out_size ))) return STATUS_NO_MEMORY;
|
||||
|
||||
irp = IoAllocateIrp( device->StackSize, FALSE );
|
||||
if (!irp)
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, out_buff );
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
irpsp = IoGetNextIrpStackLocation( irp );
|
||||
irpsp->MajorFunction = IRP_MJ_QUERY_VOLUME_INFORMATION;
|
||||
irpsp->Parameters.QueryVolume.FsInformationClass = context->params.volume.info_class;
|
||||
irpsp->Parameters.QueryVolume.Length = out_size;
|
||||
irpsp->DeviceObject = NULL;
|
||||
irpsp->CompletionRoutine = NULL;
|
||||
irpsp->FileObject = file;
|
||||
irp->AssociatedIrp.SystemBuffer = out_buff;
|
||||
irp->RequestorMode = KernelMode;
|
||||
irp->UserBuffer = out_buff;
|
||||
irp->UserIosb = NULL;
|
||||
irp->UserEvent = NULL;
|
||||
irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
|
||||
irp->Tail.Overlay.OriginalFileObject = file;
|
||||
irp->RequestorMode = UserMode;
|
||||
context->in_buff = NULL;
|
||||
|
||||
irp->Flags |= IRP_DEALLOCATE_BUFFER; /* deallocate out_buff */
|
||||
dispatch_irp( device, irp, context );
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS dispatch_free( struct dispatch_context *context )
|
||||
{
|
||||
void *obj = wine_server_get_ptr( context->params.free.obj );
|
||||
|
@ -791,6 +840,7 @@ static const dispatch_func dispatch_funcs[] =
|
|||
dispatch_write, /* IRP_CALL_WRITE */
|
||||
dispatch_flush, /* IRP_CALL_FLUSH */
|
||||
dispatch_ioctl, /* IRP_CALL_IOCTL */
|
||||
dispatch_volume, /* IRP_CALL_VOLUME */
|
||||
dispatch_free, /* IRP_CALL_FREE */
|
||||
dispatch_cancel /* IRP_CALL_CANCEL */
|
||||
};
|
||||
|
|
|
@ -2467,6 +2467,47 @@ static NTSTATUS WINAPI driver_QueryInformation(DEVICE_OBJECT *device, IRP *irp)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static NTSTATUS WINAPI driver_QueryVolumeInformation(DEVICE_OBJECT *device, IRP *irp)
|
||||
{
|
||||
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
|
||||
ULONG length = stack->Parameters.QueryVolume.Length;
|
||||
NTSTATUS ret;
|
||||
|
||||
switch (stack->Parameters.QueryVolume.FsInformationClass)
|
||||
{
|
||||
case FileFsVolumeInformation:
|
||||
{
|
||||
FILE_FS_VOLUME_INFORMATION *info = irp->AssociatedIrp.SystemBuffer;
|
||||
static const WCHAR label[] = L"WineTestDriver";
|
||||
ULONG serial = 0xdeadbeef;
|
||||
|
||||
if (length < sizeof(FILE_FS_VOLUME_INFORMATION))
|
||||
{
|
||||
ret = STATUS_INFO_LENGTH_MISMATCH;
|
||||
break;
|
||||
}
|
||||
|
||||
info->VolumeCreationTime.QuadPart = 0;
|
||||
info->VolumeSerialNumber = serial;
|
||||
info->VolumeLabelLength = min( lstrlenW(label) * sizeof(WCHAR),
|
||||
length - offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) );
|
||||
info->SupportsObjects = TRUE;
|
||||
memcpy( info->VolumeLabel, label, info->VolumeLabelLength );
|
||||
|
||||
irp->IoStatus.Information = offsetof( FILE_FS_VOLUME_INFORMATION, VolumeLabel ) + info->VolumeLabelLength;
|
||||
ret = STATUS_SUCCESS;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ret = STATUS_NOT_IMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
irp->IoStatus.Status = ret;
|
||||
IoCompleteRequest(irp, IO_NO_INCREMENT);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static NTSTATUS WINAPI driver_Close(DEVICE_OBJECT *device, IRP *irp)
|
||||
{
|
||||
IO_STACK_LOCATION *stack = IoGetCurrentIrpStackLocation(irp);
|
||||
|
@ -2509,6 +2550,7 @@ NTSTATUS WINAPI DriverEntry(DRIVER_OBJECT *driver, PUNICODE_STRING registry)
|
|||
driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = driver_IoControl;
|
||||
driver->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = driver_FlushBuffers;
|
||||
driver->MajorFunction[IRP_MJ_QUERY_INFORMATION] = driver_QueryInformation;
|
||||
driver->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = driver_QueryVolumeInformation;
|
||||
driver->MajorFunction[IRP_MJ_CLOSE] = driver_Close;
|
||||
|
||||
RtlInitUnicodeString(&nameW, L"IoDriverObjectType");
|
||||
|
|
|
@ -502,6 +502,7 @@ static void test_object_info(void)
|
|||
char buffer[200];
|
||||
OBJECT_NAME_INFORMATION *name_info = (OBJECT_NAME_INFORMATION *)buffer;
|
||||
OBJECT_TYPE_INFORMATION *type_info = (OBJECT_TYPE_INFORMATION *)buffer;
|
||||
FILE_FS_VOLUME_INFORMATION *volume_info = (FILE_FS_VOLUME_INFORMATION *)buffer;
|
||||
FILE_NAME_INFORMATION *file_info = (FILE_NAME_INFORMATION *)buffer;
|
||||
HANDLE file;
|
||||
NTSTATUS status;
|
||||
|
@ -521,6 +522,9 @@ static void test_object_info(void)
|
|||
status = NtQueryInformationFile(device, &io, buffer, sizeof(buffer), FileNameInformation);
|
||||
todo_wine ok(status == STATUS_INVALID_DEVICE_REQUEST, "got %#x\n", status);
|
||||
|
||||
status = NtQueryVolumeInformationFile(device, &io, buffer, sizeof(buffer), FileFsVolumeInformation);
|
||||
todo_wine ok(status == STATUS_INVALID_DEVICE_REQUEST, "got %#x\n", status);
|
||||
|
||||
file = CreateFileA("\\\\.\\WineTestDriver\\subfile", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
todo_wine ok(file != INVALID_HANDLE_VALUE, "got error %u\n", GetLastError());
|
||||
if (file == INVALID_HANDLE_VALUE) return;
|
||||
|
@ -554,6 +558,13 @@ static void test_object_info(void)
|
|||
ok(compare_unicode_string(file_info->FileName, file_info->FileNameLength, L"\\subfile"),
|
||||
"wrong name %s\n", debugstr_wn(file_info->FileName, file_info->FileNameLength / sizeof(WCHAR)));
|
||||
|
||||
status = NtQueryVolumeInformationFile(file, &io, buffer, sizeof(buffer), FileFsVolumeInformation);
|
||||
ok(!status, "got %#x\n", status);
|
||||
ok(volume_info->VolumeSerialNumber == 0xdeadbeef,
|
||||
"wrong serial number 0x%08x\n", volume_info->VolumeSerialNumber);
|
||||
ok(compare_unicode_string(volume_info->VolumeLabel, volume_info->VolumeLabelLength, L"WineTestDriver"),
|
||||
"wrong name %s\n", debugstr_wn(volume_info->VolumeLabel, volume_info->VolumeLabelLength / sizeof(WCHAR)));
|
||||
|
||||
CloseHandle(file);
|
||||
|
||||
file = CreateFileA("\\\\.\\WineTestDriver\\notimpl", 0, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
|
|
@ -680,6 +680,7 @@ enum irp_type
|
|||
IRP_CALL_WRITE,
|
||||
IRP_CALL_FLUSH,
|
||||
IRP_CALL_IOCTL,
|
||||
IRP_CALL_VOLUME,
|
||||
IRP_CALL_FREE,
|
||||
IRP_CALL_CANCEL
|
||||
};
|
||||
|
@ -733,6 +734,14 @@ typedef union
|
|||
client_ptr_t file;
|
||||
} ioctl;
|
||||
struct
|
||||
{
|
||||
enum irp_type type;
|
||||
unsigned int info_class;
|
||||
data_size_t out_size;
|
||||
int __pad;
|
||||
client_ptr_t file;
|
||||
} volume;
|
||||
struct
|
||||
{
|
||||
enum irp_type type;
|
||||
int __pad;
|
||||
|
@ -6269,7 +6278,7 @@ union generic_reply
|
|||
|
||||
/* ### protocol_version begin ### */
|
||||
|
||||
#define SERVER_PROTOCOL_VERSION 676
|
||||
#define SERVER_PROTOCOL_VERSION 677
|
||||
|
||||
/* ### protocol_version end ### */
|
||||
|
||||
|
|
|
@ -207,6 +207,7 @@ static int device_file_write( struct fd *fd, struct async *async, file_pos_t pos
|
|||
static int device_file_flush( struct fd *fd, struct async *async );
|
||||
static int device_file_ioctl( struct fd *fd, ioctl_code_t code, struct async *async );
|
||||
static void device_file_reselect_async( struct fd *fd, struct async_queue *queue );
|
||||
static int device_file_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class );
|
||||
|
||||
static const struct object_ops device_file_ops =
|
||||
{
|
||||
|
@ -241,7 +242,7 @@ static const struct fd_ops device_file_fd_ops =
|
|||
device_file_write, /* write */
|
||||
device_file_flush, /* flush */
|
||||
default_fd_get_file_info, /* get_file_info */
|
||||
no_fd_get_volume_info, /* get_volume_info */
|
||||
device_file_get_volume_info, /* get_volume_info */
|
||||
device_file_ioctl, /* ioctl */
|
||||
default_fd_queue_async, /* queue_async */
|
||||
device_file_reselect_async /* reselect_async */
|
||||
|
@ -594,6 +595,10 @@ static int fill_irp_params( struct device_manager *manager, struct irp_call *irp
|
|||
irp->params.ioctl.file = get_kernel_object_ptr( manager, &irp->file->obj );
|
||||
irp->params.ioctl.out_size = irp->iosb->out_size;
|
||||
break;
|
||||
case IRP_CALL_VOLUME:
|
||||
irp->params.volume.file = get_kernel_object_ptr( manager, &irp->file->obj );
|
||||
irp->params.volume.out_size = irp->iosb->out_size;
|
||||
break;
|
||||
}
|
||||
|
||||
*params = irp->params;
|
||||
|
@ -631,6 +636,17 @@ static enum server_fd_type device_file_get_fd_type( struct fd *fd )
|
|||
return FD_TYPE_DEVICE;
|
||||
}
|
||||
|
||||
static int device_file_get_volume_info( struct fd *fd, struct async *async, unsigned int info_class )
|
||||
{
|
||||
struct device_file *file = get_fd_user( fd );
|
||||
irp_params_t params;
|
||||
|
||||
memset( ¶ms, 0, sizeof(params) );
|
||||
params.volume.type = IRP_CALL_VOLUME;
|
||||
params.volume.info_class = info_class;
|
||||
return queue_irp( file, ¶ms, async );
|
||||
}
|
||||
|
||||
static int device_file_read( struct fd *fd, struct async *async, file_pos_t pos )
|
||||
{
|
||||
struct device_file *file = get_fd_user( fd );
|
||||
|
|
|
@ -696,6 +696,7 @@ enum irp_type
|
|||
IRP_CALL_WRITE,
|
||||
IRP_CALL_FLUSH,
|
||||
IRP_CALL_IOCTL,
|
||||
IRP_CALL_VOLUME,
|
||||
IRP_CALL_FREE,
|
||||
IRP_CALL_CANCEL
|
||||
};
|
||||
|
@ -749,6 +750,14 @@ typedef union
|
|||
client_ptr_t file; /* opaque ptr for the file object */
|
||||
} ioctl;
|
||||
struct
|
||||
{
|
||||
enum irp_type type; /* IRP_CALL_VOLUME */
|
||||
unsigned int info_class;/* information class */
|
||||
data_size_t out_size; /* needed output size */
|
||||
int __pad;
|
||||
client_ptr_t file; /* opaque ptr for the file object */
|
||||
} volume;
|
||||
struct
|
||||
{
|
||||
enum irp_type type; /* IRP_CALL_FREE */
|
||||
int __pad;
|
||||
|
|
|
@ -381,6 +381,12 @@ static void dump_irp_params( const char *prefix, const irp_params_t *data )
|
|||
dump_uint64( ",file=", &data->ioctl.file );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case IRP_CALL_VOLUME:
|
||||
fprintf( stderr, "%s{VOLUME,class=%u,out_size=%u", prefix,
|
||||
data->volume.info_class, data->volume.out_size );
|
||||
dump_uint64( ",file=", &data->volume.file );
|
||||
fputc( '}', stderr );
|
||||
break;
|
||||
case IRP_CALL_FREE:
|
||||
fprintf( stderr, "%s{FREE", prefix );
|
||||
dump_uint64( ",obj=", &data->free.obj );
|
||||
|
|
Loading…
Reference in New Issue