[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH] Report version details to XenStore
Requires adding the XENBUS_STORE and XENBUS_SUSPEND interface to add the version details, and deal with re-adding after a suspend/resume. Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx> --- include/revision.h | 11 +- include/store_interface.h | 348 +++++++++++++++++++++++++++++ include/suspend_interface.h | 177 +++++++++++++++ src/coinst/coinst.c | 2 +- src/xenhid.inf | 6 +- src/xenhid/fdo.c | 510 +++++++++++++++++++++++++++++++++++++++++-- src/xenhid/string.c | 467 +++++++++++++++++++++++++++++++++++++++ src/xenhid/string.h | 51 +++++ vs2015/xenhid/xenhid.vcxproj | 1 + vs2017/xenhid/xenhid.vcxproj | 1 + 10 files changed, 1547 insertions(+), 27 deletions(-) create mode 100644 include/store_interface.h create mode 100644 include/suspend_interface.h create mode 100644 src/xenhid/string.c create mode 100644 src/xenhid/string.h diff --git a/include/revision.h b/include/revision.h index b30aee7..d81a16a 100644 --- a/include/revision.h +++ b/include/revision.h @@ -34,12 +34,13 @@ // Key: // H - XENHID_HID_INTERFACE +// ST - XENBUS_STORE_INTERFACE +// SU - XENBUS_SUSPEND_INTERFACE // REVISION H -#define DEFINE_REVISION_TABLE \ - DEFINE_REVISION(0x0800000B, 1), \ - DEFINE_REVISION(0x0800000C, 1), \ - DEFINE_REVISION(0x0800000D, 1), \ - DEFINE_REVISION(0x09000000, 1) +#define DEFINE_REVISION_TABLE \ + DEFINE_REVISION(0x09000000, 1, 0, 0), \ + DEFINE_REVISION(0x09000001, 1, 1, 1), \ + DEFINE_REVISION(0x09000002, 1, 2, 1) #endif // _REVISION_H diff --git a/include/store_interface.h b/include/store_interface.h new file mode 100644 index 0000000..52f1a1d --- /dev/null +++ b/include/store_interface.h @@ -0,0 +1,348 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*! \file store_interface.h + \brief XENBUS STORE Interface + + This interface provides access to XenStore +*/ + +#ifndef _XENBUS_STORE_INTERFACE_H +#define _XENBUS_STORE_INTERFACE_H + +#ifndef _WINDLL + +/*! \typedef XENBUS_STORE_TRANSACTION + \brief XenStore transaction handle +*/ +typedef struct _XENBUS_STORE_TRANSACTION XENBUS_STORE_TRANSACTION, *PXENBUS_STORE_TRANSACTION; + +/*! \typedef XENBUS_STORE_WATCH + \brief XenStore watch handle +*/ +typedef struct _XENBUS_STORE_WATCH XENBUS_STORE_WATCH, *PXENBUS_STORE_WATCH; + +/*! \typedef XENBUS_STORE_PERMISSION_MASK + \brief Bitmask of XenStore key permissions +*/ +typedef enum _XENBUS_STORE_PERMISSION_MASK { + XENBUS_STORE_PERM_NONE = 0, + XENBUS_STORE_PERM_READ = 1, + XENBUS_STORE_PERM_WRITE = 2, +} XENBUS_STORE_PERMISSION_MASK; + +/*! \typedef XENBUS_STORE_PERMISSION + \brief XenStore key permissions entry for a single domain +*/ +typedef struct _XENBUS_STORE_PERMISSION { + USHORT Domain; + XENBUS_STORE_PERMISSION_MASK Mask; +} XENBUS_STORE_PERMISSION, *PXENBUS_STORE_PERMISSION; + +/*! \typedef XENBUS_STORE_ACQUIRE + \brief Acquire a reference to the STORE interface + + \param Interface The interface header +*/ +typedef NTSTATUS +(*XENBUS_STORE_ACQUIRE)( + IN PINTERFACE Interface + ); + +/*! \typedef XENBUS_STORE_RELEASE + \brief Release a reference to the STORE interface + + \param Interface The interface header +*/ +typedef VOID +(*XENBUS_STORE_RELEASE)( + IN PINTERFACE Interface + ); + +/*! \typedef XENBUS_STORE_FREE + \brief Free a memory buffer allocated by the STORE interface + + \param Interface The interface header + \param Buffer Pointer to the memory buffer +*/ +typedef VOID +(*XENBUS_STORE_FREE)( + IN PINTERFACE Interface, + IN PCHAR Buffer + ); + +/*! \typedef XENBUS_STORE_READ + \brief Read a value from XenStore + + \param Interface The interface header + \param Transaction The transaction handle (NULL if this read is not + part of a transaction) + \param Prefix An optional prefix for the \a Node + \param Node The concatenation of the \a Prefix and this value specifies + the XenStore key to read + \param A pointer to a pointer that will be initialized with a memory + buffer containing the value read + + The \a Buffer should be freed using \a XENBUS_STORE_FREE +*/ +typedef NTSTATUS +(*XENBUS_STORE_READ)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL, + IN PCHAR Prefix OPTIONAL, + IN PCHAR Node, + OUT PCHAR *Buffer + ); + +/*! \typedef XENBUS_STORE_PRINTF + \brief Write a value to XenStore + + \param Interface The interface header + \param Transaction The transaction handle (NULL if this write is not + part of a transaction) + \param Prefix An optional prefix for the \a Node + \param Node The concatenation of the \a Prefix and this value specifies + the XenStore key to write + \param Format A format specifier + \param ... Additional parameters required by \a Format + + If the \a Node does not exist then it is created +*/ +typedef NTSTATUS +(*XENBUS_STORE_PRINTF)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL, + IN PCHAR Prefix OPTIONAL, + IN PCHAR Node, + IN const CHAR *Format, + ... + ); + +/*! \typedef XENBUS_STORE_REMOVE + \brief Remove a key from XenStore + + \param Interface The interface header + \param Transaction The transaction handle (NULL if this removal is not + part of a transaction) + \param Prefix An optional prefix for the \a Node + \param Node The concatenation of the \a Prefix and this value specifies + the XenStore key to remove +*/ +typedef NTSTATUS +(*XENBUS_STORE_REMOVE)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL, + IN PCHAR Prefix OPTIONAL, + IN PCHAR Node + ); + +/*! \typedef XENBUS_STORE_DIRECTORY + \brief Enumerate all immediate child keys of a XenStore key + + \param Interface The interface header + \param Transaction The transaction handle (NULL if this removal is not + part of a transaction) + \param Prefix An optional prefix for the \a Node + \param Node The concatenation of the \a Prefix and this value specifies + the XenStore key to enumerate + \param A pointer to a pointer that will be initialized with a memory + buffer containing a NUL separated list of key names + + The \a Buffer should be freed using \a XENBUS_STORE_FREE +*/ +typedef NTSTATUS +(*XENBUS_STORE_DIRECTORY)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL, + IN PCHAR Prefix OPTIONAL, + IN PCHAR Node, + OUT PCHAR *Buffer + ); + +/*! \typedef XENBUS_STORE_TRANSACTION_START + \brief Start a XenStore transaction + + \param Interface The interface header + \param Transaction Pointer to a transaction handle to be initialized +*/ +typedef NTSTATUS +(*XENBUS_STORE_TRANSACTION_START)( + IN PINTERFACE Interface, + OUT PXENBUS_STORE_TRANSACTION *Transaction + ); + +/*! \typedef XENBUS_STORE_TRANSACTION_END + \brief End a XenStore transaction + + \param Interface The interface header + \param Transaction The transaction handle + \param Commit Set to TRUE if actions performed within the transaction should + be made visible, or FALSE if they should not be + + If \a Commit is TRUE and the transaction to found to clash then + STATUS_RETRY will be returned +*/ +typedef NTSTATUS +(*XENBUS_STORE_TRANSACTION_END)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_TRANSACTION Transaction, + IN BOOLEAN Commit + ); + +/*! \typedef XENBUS_STORE_WATCH_ADD + \brief Add a XenStore watch + + \param Interface The interface header + \param Prefix An optional prefix for the \a Node + \param Node The concatenation of the \a Prefix and this value specifies + the XenStore key to watch + \param Event A pointer to an event object to be signalled when the + watch fires + \param Watch A pointer to a watch handle to be initialized +*/ +typedef NTSTATUS +(*XENBUS_STORE_WATCH_ADD)( + IN PINTERFACE Interface, + IN PCHAR Prefix OPTIONAL, + IN PCHAR Node, + IN PKEVENT Event, + OUT PXENBUS_STORE_WATCH *Watch + ); + +/*! \typedef XENBUS_STORE_WATCH_REMOVE + \brief Remove a XenStore watch + + \param Interface The interface header + \param Watch The watch handle +*/ +typedef NTSTATUS +(*XENBUS_STORE_WATCH_REMOVE)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_WATCH Watch + ); + +/*! \typedef XENBUS_STORE_POLL + \brief Poll for XenStore activity + + \param Interface The interface header + + If it is necessary to spin at DISPATCH_LEVEL waiting for XenStore + activity then this will block the normal STORE interface DPC so this + method must be regularly invoked during the spin loop to check for + XenStore activity +*/ +typedef VOID +(*XENBUS_STORE_POLL)( + IN PINTERFACE Interface + ); + +/*! \typedef XENBUS_STORE_PERMISSIONS_SET + \brief Set permissions for a XenStore key + + \param Interface The interface header + \param Transaction The transaction handle (NULL if this is not + part of a transaction) + \param Prefix An optional prefix for the \a Node + \param Node The concatenation of the \a Prefix and this value specifies + the XenStore key to set permissions of + \param Permissions An array of permissions to set + \param NumberPermissions Number of elements in the \a Permissions array +*/ +typedef NTSTATUS +(*XENBUS_STORE_PERMISSIONS_SET)( + IN PINTERFACE Interface, + IN PXENBUS_STORE_TRANSACTION Transaction OPTIONAL, + IN PCHAR Prefix OPTIONAL, + IN PCHAR Node, + IN PXENBUS_STORE_PERMISSION Permissions, + IN ULONG NumberPermissions + ); + +// {86824C3B-D34E-4753-B281-2F1E3AD214D7} +DEFINE_GUID(GUID_XENBUS_STORE_INTERFACE, +0x86824c3b, 0xd34e, 0x4753, 0xb2, 0x81, 0x2f, 0x1e, 0x3a, 0xd2, 0x14, 0xd7); + +/*! \struct _XENBUS_STORE_INTERFACE_V1 + \brief STORE interface version 1 + \ingroup interfaces +*/ +struct _XENBUS_STORE_INTERFACE_V1 { + INTERFACE Interface; + XENBUS_STORE_ACQUIRE StoreAcquire; + XENBUS_STORE_RELEASE StoreRelease; + XENBUS_STORE_FREE StoreFree; + XENBUS_STORE_READ StoreRead; + XENBUS_STORE_PRINTF StorePrintf; + XENBUS_STORE_REMOVE StoreRemove; + XENBUS_STORE_DIRECTORY StoreDirectory; + XENBUS_STORE_TRANSACTION_START StoreTransactionStart; + XENBUS_STORE_TRANSACTION_END StoreTransactionEnd; + XENBUS_STORE_WATCH_ADD StoreWatchAdd; + XENBUS_STORE_WATCH_REMOVE StoreWatchRemove; + XENBUS_STORE_POLL StorePoll; +}; + +/*! \struct _XENBUS_STORE_INTERFACE_V2 + \brief STORE interface version 2 + \ingroup interfaces +*/ +struct _XENBUS_STORE_INTERFACE_V2 { + INTERFACE Interface; + XENBUS_STORE_ACQUIRE StoreAcquire; + XENBUS_STORE_RELEASE StoreRelease; + XENBUS_STORE_FREE StoreFree; + XENBUS_STORE_READ StoreRead; + XENBUS_STORE_PRINTF StorePrintf; + XENBUS_STORE_PERMISSIONS_SET StorePermissionsSet; + XENBUS_STORE_REMOVE StoreRemove; + XENBUS_STORE_DIRECTORY StoreDirectory; + XENBUS_STORE_TRANSACTION_START StoreTransactionStart; + XENBUS_STORE_TRANSACTION_END StoreTransactionEnd; + XENBUS_STORE_WATCH_ADD StoreWatchAdd; + XENBUS_STORE_WATCH_REMOVE StoreWatchRemove; + XENBUS_STORE_POLL StorePoll; +}; + +typedef struct _XENBUS_STORE_INTERFACE_V2 XENBUS_STORE_INTERFACE, *PXENBUS_STORE_INTERFACE; + +/*! \def XENBUS_STORE + \brief Macro at assist in method invocation +*/ +#define XENBUS_STORE(_Method, _Interface, ...) \ + (_Interface)->Store ## _Method((PINTERFACE)(_Interface), __VA_ARGS__) + +#endif // _WINDLL + +#define XENBUS_STORE_INTERFACE_VERSION_MIN 1 +#define XENBUS_STORE_INTERFACE_VERSION_MAX 2 + +#endif // _XENBUS_STORE_INTERFACE_H + diff --git a/include/suspend_interface.h b/include/suspend_interface.h new file mode 100644 index 0000000..cbe11ab --- /dev/null +++ b/include/suspend_interface.h @@ -0,0 +1,177 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/*! \file suspend_interface.h + \brief XENBUS SUSPEND Interface + + This interface provides primitives to handle VM suspend/resume +*/ + +#ifndef _XENBUS_SUSPEND_INTERFACE_H +#define _XENBUS_SUSPEND_INTERFACE_H + +#ifndef _WINDLL + +/*! \enum _XENBUS_SUSPEND_CALLBACK_TYPE + \brief Suspend callback type to be registered +*/ +typedef enum _XENBUS_SUSPEND_CALLBACK_TYPE { + SUSPEND_CALLBACK_TYPE_INVALID = 0, + SUSPEND_CALLBACK_EARLY, /*!< Early */ + SUSPEND_CALLBACK_LATE /*!< Late */ +} XENBUS_SUSPEND_CALLBACK_TYPE, *PXENBUS_SUSPEND_CALLBACK_TYPE; + +/*! \typedef XENBUS_SUSPEND_CALLBACK + \brief Suspend callback handle +*/ +typedef struct _XENBUS_SUSPEND_CALLBACK XENBUS_SUSPEND_CALLBACK, *PXENBUS_SUSPEND_CALLBACK; + +/*! \typedef XENBUS_SUSPEND_ACQUIRE + \brief Acquire a reference to the SUSPEND interface + + \param Interface The interface header +*/ +typedef NTSTATUS +(*XENBUS_SUSPEND_ACQUIRE)( + IN PINTERFACE Interface + ); + +/*! \typedef XENBUS_SUSPEND_RELEASE + \brief Release a reference to the SUSPEND interface + + \param Interface The interface header +*/ +typedef VOID +(*XENBUS_SUSPEND_RELEASE)( + IN PINTERFACE Interface + ); + +/*! \typedef XENBUS_SUSPEND_FUNCTION + \brief Suspend callback function + + \param Argument Context \a Argument supplied to \a XENBUS_SUSPEND_REGISTER + + Suspend callback functions are always invoked on one vCPU with all other + vCPUs corralled at the same IRQL as the callback. \a Early callback + functions are always invoked with IRQL == HIGH_LEVEL and \a Late callback + functions are always invoked with IRQL == DISPATCH_LEVEL +*/ +typedef VOID +(*XENBUS_SUSPEND_FUNCTION)( + IN PVOID Argument + ); + +/*! \typedef XENBUS_SUSPEND_REGISTER + \brief Register a suspend callback function + + \param Interface The interface header + \param Type The type of callback function to register + \param Function The callback function + \param Argument An optional context argument passed to the callback + \param Callback A pointer to a callback handle to be initialized +*/ +typedef NTSTATUS +(*XENBUS_SUSPEND_REGISTER)( + IN PINTERFACE Interface, + IN XENBUS_SUSPEND_CALLBACK_TYPE Type, + IN XENBUS_SUSPEND_FUNCTION Function, + IN PVOID Argument OPTIONAL, + OUT PXENBUS_SUSPEND_CALLBACK *Callback + ); + +/*! \typedef XENBUS_SUSPEND_DEREGISTER + \brief Deregister a suspend callback function + + \param Interface The interface header + \param Callback The callback handle +*/ +typedef VOID +(*XENBUS_SUSPEND_DEREGISTER)( + IN PINTERFACE Interface, + IN PXENBUS_SUSPEND_CALLBACK Callback + ); + +/*! \typedef XENBUS_SUSPEND_TRIGGER + \brief Trigger a VM suspend + + \param Interface The interface header + + This method must always be invoked with IRQL == PASSIVE_LEVEL +*/ +typedef NTSTATUS +(*XENBUS_SUSPEND_TRIGGER)( + IN PINTERFACE Interface + ); + +/*! \typedef XENBUS_SUSPEND_GET_COUNT + \brief Get the number of VM suspends that have occurred since boot + + \param Interface The interface header + \return The number of VM suspends +*/ +typedef ULONG +(*XENBUS_SUSPEND_GET_COUNT)( + IN PINTERFACE Interface + ); + +// {0554F2AF-B510-4C71-AC03-1C503E394238} +DEFINE_GUID(GUID_XENBUS_SUSPEND_INTERFACE, +0x554f2af, 0xb510, 0x4c71, 0xac, 0x3, 0x1c, 0x50, 0x3e, 0x39, 0x42, 0x38); + +/*! \struct _XENBUS_SUSPEND_INTERFACE_V1 + \brief SUSPEND interface version 1 + \ingroup interfaces +*/ +struct _XENBUS_SUSPEND_INTERFACE_V1 { + INTERFACE Interface; + XENBUS_SUSPEND_ACQUIRE Acquire; + XENBUS_SUSPEND_RELEASE Release; + XENBUS_SUSPEND_REGISTER Register; + XENBUS_SUSPEND_DEREGISTER Deregister; + XENBUS_SUSPEND_TRIGGER Trigger; + XENBUS_SUSPEND_GET_COUNT GetCount; +}; + +typedef struct _XENBUS_SUSPEND_INTERFACE_V1 XENBUS_SUSPEND_INTERFACE, *PXENBUS_SUSPEND_INTERFACE; + +/*! \def XENBUS_SUSPEND + \brief Macro at assist in method invocation +*/ +#define XENBUS_SUSPEND(_Method, _Interface, ...) \ + (_Interface)-> ## _Method((PINTERFACE)(_Interface), __VA_ARGS__) + +#endif // _WINDLL + +#define XENBUS_SUSPEND_INTERFACE_VERSION_MIN 1 +#define XENBUS_SUSPEND_INTERFACE_VERSION_MAX 1 + +#endif // _XENBUS_SUSPEND_INTERFACE_H + diff --git a/src/coinst/coinst.c b/src/coinst/coinst.c index b3368c9..56e566b 100644 --- a/src/coinst/coinst.c +++ b/src/coinst/coinst.c @@ -677,7 +677,7 @@ fail1: return FALSE; } -#define DEFINE_REVISION(_N, _H) \ +#define DEFINE_REVISION(_N, _H, _ST, _SU) \ (_N) static DWORD DeviceRevision[] = { diff --git a/src/xenhid.inf b/src/xenhid.inf index d440876..e1f0e28 100644 --- a/src/xenhid.inf +++ b/src/xenhid.inf @@ -59,9 +59,9 @@ xenhid_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll ; DisplayName Section DeviceID ; ----------- ------- -------- -%XenHidName% =XenHid_Inst, XENVKBD\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_HID&REV_09000000 -%XenHidName% =XenHid_Inst, XENVKBD\VEN_@VENDOR_PREFIX@0001&DEV_HID&REV_09000000 -%XenHidName% =XenHid_Inst, XENVKBD\VEN_@VENDOR_PREFIX@0002&DEV_HID&REV_09000000 +%XenHidName% =XenHid_Inst, XENVKBD\VEN_@VENDOR_PREFIX@@VENDOR_DEVICE_ID@&DEV_HID&REV_09000001 +%XenHidName% =XenHid_Inst, XENVKBD\VEN_@VENDOR_PREFIX@0001&DEV_HID&REV_09000001 +%XenHidName% =XenHid_Inst, XENVKBD\VEN_@VENDOR_PREFIX@0002&DEV_HID&REV_09000001 [XenHid_Inst] CopyFiles=XenHid_Copyfiles diff --git a/src/xenhid/fdo.c b/src/xenhid/fdo.c index f70d71a..c897185 100644 --- a/src/xenhid/fdo.c +++ b/src/xenhid/fdo.c @@ -34,25 +34,36 @@ #include <procgrp.h> #include <ntstrsafe.h> #include <hidport.h> +#include <version.h> #include <hid_interface.h> +#include <store_interface.h> +#include <suspend_interface.h> #include "fdo.h" #include "driver.h" #include "dbg_print.h" #include "assert.h" #include "util.h" +#include "string.h" + +#define MAXNAMELEN 128 struct _XENHID_FDO { - PDEVICE_OBJECT DeviceObject; - PDEVICE_OBJECT LowerDeviceObject; - BOOLEAN Enabled; - XENHID_HID_INTERFACE HidInterface; - IO_CSQ Queue; - KSPIN_LOCK Lock; - LIST_ENTRY List; + PDEVICE_OBJECT DeviceObject; + PDEVICE_OBJECT LowerDeviceObject; + BOOLEAN Enabled; + XENHID_HID_INTERFACE HidInterface; + XENBUS_STORE_INTERFACE StoreInterface; + XENBUS_SUSPEND_INTERFACE SuspendInterface; + PXENBUS_SUSPEND_CALLBACK SuspendCallback; + IO_CSQ Queue; + KSPIN_LOCK Lock; + LIST_ENTRY List; }; +#define FDO_POOL_TAG 'ODF' + ULONG FdoGetSize( VOID @@ -186,6 +197,390 @@ done: return Completed; } + +static FORCEINLINE PVOID +__FdoAllocate( + IN ULONG Length + ) +{ + PVOID Buffer; + + Buffer = ExAllocatePoolWithTag(NonPagedPool, Length, FDO_POOL_TAG); + if (Buffer) + RtlZeroMemory(Buffer, Length); + + return Buffer; +} + +static FORCEINLINE VOID +__FdoFree( + IN PVOID Buffer + ) +{ + ExFreePoolWithTag(Buffer, FDO_POOL_TAG); +} + +static FORCEINLINE PANSI_STRING +__FdoMultiSzToUpcaseAnsi( + IN PCHAR Buffer +) +{ + PANSI_STRING Ansi; + LONG Index; + LONG Count; + NTSTATUS status; + + Index = 0; + Count = 0; + for (;;) { + if (Buffer[Index] == '\0') { + Count++; + Index++; + + // Check for double NUL + if (Buffer[Index] == '\0') + break; + } + else { + Buffer[Index] = __toupper(Buffer[Index]); + Index++; + } + } + + Ansi = __FdoAllocate(sizeof(ANSI_STRING) * (Count + 1)); + + status = STATUS_NO_MEMORY; + if (Ansi == NULL) + goto fail1; + + for (Index = 0; Index < Count; Index++) { + ULONG Length; + + Length = (ULONG)strlen(Buffer); + Ansi[Index].MaximumLength = (USHORT)(Length + 1); + Ansi[Index].Buffer = __FdoAllocate(Ansi[Index].MaximumLength); + + status = STATUS_NO_MEMORY; + if (Ansi[Index].Buffer == NULL) + goto fail2; + + RtlCopyMemory(Ansi[Index].Buffer, Buffer, Length); + Ansi[Index].Length = (USHORT)Length; + + Buffer += Length + 1; + } + + return Ansi; + +fail2: + Error("fail2\n"); + + while (--Index >= 0) + __FdoFree(Ansi[Index].Buffer); + + __FdoFree(Ansi); + +fail1: + Error("fail1 (%08x)\n", status); + + return NULL; +} + +static FORCEINLINE VOID +__FdoFreeAnsi( + IN PANSI_STRING Ansi + ) +{ + ULONG Index; + + for (Index = 0; Ansi[Index].Buffer != NULL; Index++) + __FdoFree(Ansi[Index].Buffer); + + __FdoFree(Ansi); +} + +static FORCEINLINE BOOLEAN +__FdoMatchDistribution( + IN PXENHID_FDO Fdo, + IN PCHAR Buffer +) +{ + PCHAR Vendor; + PCHAR Product; + PCHAR Context; + const CHAR *Text; + BOOLEAN Match; + ULONG Index; + NTSTATUS status; + + UNREFERENCED_PARAMETER(Fdo); + + status = STATUS_INVALID_PARAMETER; + + Vendor = __strtok_r(Buffer, " ", &Context); + if (Vendor == NULL) + goto fail1; + + Product = __strtok_r(NULL, " ", &Context); + if (Product == NULL) + goto fail2; + + Match = TRUE; + + Text = VENDOR_NAME_STR; + + for (Index = 0; Text[Index] != 0; Index++) { + if (!isalnum((UCHAR)Text[Index])) { + if (Vendor[Index] != '_') { + Match = FALSE; + break; + } + } else { + if (Vendor[Index] != Text[Index]) { + Match = FALSE; + break; + } + } + } + + Text = "XENHID"; + + if (_stricmp(Product, Text) != 0) + Match = FALSE; + + return Match; + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + return FALSE; +} + +#define MAXIMUM_INDEX 255 + +static FORCEINLINE NTSTATUS +__FdoSetDistribution( + IN PXENHID_FDO Fdo + ) +{ + ULONG Index; + CHAR Distribution[MAXNAMELEN]; + CHAR Vendor[MAXNAMELEN]; + STRING String; + const CHAR *Product; + NTSTATUS status; + + Trace("====>\n"); + + Index = 0; + while (Index <= MAXIMUM_INDEX) { + PCHAR Buffer; + + String.Buffer = Distribution; + String.MaximumLength = sizeof(Distribution); + String.Length = 0; + + status = StringPrintf(&String, + "%u", + Index); + ASSERT(NT_SUCCESS(status)); + + status = XENBUS_STORE(Read, + &Fdo->StoreInterface, + NULL, + "drivers", + Distribution, + &Buffer); + if (!NT_SUCCESS(status)) { + if (status == STATUS_OBJECT_NAME_NOT_FOUND) + goto update; + + goto fail1; + } + + XENBUS_STORE(Free, + &Fdo->StoreInterface, + Buffer); + + Index++; + } + + status = STATUS_UNSUCCESSFUL; + goto fail2; + +update: + String.Buffer = Vendor; + String.MaximumLength = sizeof(Vendor); + String.Length = 0; + + status = StringPrintf(&String, + "%s", + VENDOR_NAME_STR); + ASSERT(NT_SUCCESS(status)); + + for (Index = 0; Vendor[Index] != '\0'; Index++) + if (!isalnum((UCHAR)Vendor[Index])) + Vendor[Index] = '_'; + + Product = "XENHID"; + +#if DBG +#define ATTRIBUTES "(DEBUG)" +#else +#define ATTRIBUTES "" +#endif + + (VOID)XENBUS_STORE(Printf, + &Fdo->StoreInterface, + NULL, + "drivers", + Distribution, + "%s %s %u.%u.%u.%u %s", + Vendor, + Product, + MAJOR_VERSION, + MINOR_VERSION, + MICRO_VERSION, + BUILD_NUMBER, + ATTRIBUTES + ); + +#undef ATTRIBUTES + + Trace("<====\n"); + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +static FORCEINLINE VOID +__FdoClearDistribution( + IN PXENHID_FDO Fdo + ) +{ + PCHAR Buffer; + PANSI_STRING Distributions; + ULONG Index; + NTSTATUS status; + + Trace("====>\n"); + + status = XENBUS_STORE(Directory, + &Fdo->StoreInterface, + NULL, + NULL, + "drivers", + &Buffer); + if (NT_SUCCESS(status)) { + Distributions = __FdoMultiSzToUpcaseAnsi(Buffer); + + XENBUS_STORE(Free, + &Fdo->StoreInterface, + Buffer); + } else { + Distributions = NULL; + } + + if (Distributions == NULL) + goto done; + + for (Index = 0; Distributions[Index].Buffer != NULL; Index++) { + PANSI_STRING Distribution = &Distributions[Index]; + + status = XENBUS_STORE(Read, + &Fdo->StoreInterface, + NULL, + "drivers", + Distribution->Buffer, + &Buffer); + if (!NT_SUCCESS(status)) + continue; + + if (__FdoMatchDistribution(Fdo, Buffer)) + (VOID)XENBUS_STORE(Remove, + &Fdo->StoreInterface, + NULL, + "drivers", + Distribution->Buffer); + + XENBUS_STORE(Free, + &Fdo->StoreInterface, + Buffer); + } + + __FdoFreeAnsi(Distributions); + +done: + Trace("<====\n"); +} + +static DECLSPEC_NOINLINE VOID +FdoSuspendCallback( + IN PVOID Argument + ) +{ + PXENHID_FDO Fdo = Argument; + + (VOID)__FdoSetDistribution(Fdo); +} + +static DECLSPEC_NOINLINE NTSTATUS +FdoSetDistribution( + IN PXENHID_FDO Fdo + ) +{ + NTSTATUS status; + + Trace("====>\n"); + + (VOID)__FdoSetDistribution(Fdo); + + status = XENBUS_SUSPEND(Register, + &Fdo->SuspendInterface, + SUSPEND_CALLBACK_LATE, + FdoSuspendCallback, + Fdo, + &Fdo->SuspendCallback); + if (!NT_SUCCESS(status)) + goto fail1; + + Trace("<====\n"); + return STATUS_SUCCESS; + +fail1: + Error("fail1 (%08x)\n", status); + + __FdoClearDistribution(Fdo); + + return status; +} + +static DECLSPEC_NOINLINE VOID +FdoClearDistribution( + IN PXENHID_FDO Fdo + ) +{ + Trace("====>\n"); + + XENBUS_SUSPEND(Deregister, + &Fdo->SuspendInterface, + Fdo->SuspendCallback); + Fdo->SuspendCallback = NULL; + + __FdoClearDistribution(Fdo); + + Trace("<====\n"); +} + static DECLSPEC_NOINLINE NTSTATUS FdoD3ToD0( IN PXENHID_FDO Fdo @@ -198,29 +593,60 @@ FdoD3ToD0( if (Fdo->Enabled) goto done; + status = XENBUS_STORE(Acquire, + &Fdo->StoreInterface); + if (!NT_SUCCESS(status)) + goto fail1; + + status = XENBUS_SUSPEND(Acquire, + &Fdo->SuspendInterface); + if (!NT_SUCCESS(status)) + goto fail2; + + status = FdoSetDistribution(Fdo); + if (!NT_SUCCESS(status)) + goto fail3; + status = XENHID_HID(Acquire, &Fdo->HidInterface); if (!NT_SUCCESS(status)) - goto fail1; + goto fail4; status = XENHID_HID(Enable, &Fdo->HidInterface, FdoHidCallback, Fdo); if (!NT_SUCCESS(status)) - goto fail2; + goto fail5; Fdo->Enabled = TRUE; done: Trace("<=====\n"); return STATUS_SUCCESS; -fail2: - Error("fail2\n"); +fail5: + Error("fail5\n"); XENHID_HID(Release, &Fdo->HidInterface); +fail4: + Error("fail4\n"); + + FdoClearDistribution(Fdo); + +fail3: + Error("fail3\n"); + + XENBUS_SUSPEND(Release, + &Fdo->SuspendInterface); + +fail2: + Error("fail2\n"); + + XENBUS_STORE(Release, + &Fdo->StoreInterface); + fail1: Error("fail1 %08x\n", status); return status; @@ -242,6 +668,14 @@ FdoD0ToD3( XENHID_HID(Release, &Fdo->HidInterface); + FdoClearDistribution(Fdo); + + XENBUS_SUSPEND(Release, + &Fdo->SuspendInterface); + + XENBUS_STORE(Release, + &Fdo->StoreInterface); + Fdo->Enabled = FALSE; done: Trace("<=====\n"); @@ -606,8 +1040,12 @@ FdoDispatch( } static FORCEINLINE NTSTATUS -FdoQueryHidInterface( - IN PXENHID_FDO Fdo +FdoQueryInterface( + IN PXENHID_FDO Fdo, + IN const GUID *Guid, + IN ULONG Version, + OUT PINTERFACE Interface, + IN ULONG Size ) { KEVENT Event; @@ -637,10 +1075,10 @@ FdoQueryHidInterface( StackLocation = IoGetNextIrpStackLocation(Irp); StackLocation->MinorFunction = IRP_MN_QUERY_INTERFACE; - StackLocation->Parameters.QueryInterface.InterfaceType = &GUID_XENHID_HID_INTERFACE; - StackLocation->Parameters.QueryInterface.Size = sizeof (XENHID_HID_INTERFACE); - StackLocation->Parameters.QueryInterface.Version = XENHID_HID_INTERFACE_VERSION_MAX; - StackLocation->Parameters.QueryInterface.Interface = (PINTERFACE)&Fdo->HidInterface; + StackLocation->Parameters.QueryInterface.InterfaceType = Guid; + StackLocation->Parameters.QueryInterface.Size = (USHORT)Size; + StackLocation->Parameters.QueryInterface.Version = (USHORT)Version; + StackLocation->Parameters.QueryInterface.Interface = Interface; Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; @@ -694,13 +1132,45 @@ FdoCreate( if (!NT_SUCCESS(status)) goto fail1; - status = FdoQueryHidInterface(Fdo); + status = FdoQueryInterface(Fdo, + &GUID_XENBUS_SUSPEND_INTERFACE, + XENBUS_SUSPEND_INTERFACE_VERSION_MAX, + (PINTERFACE)&Fdo->SuspendInterface, + sizeof(XENBUS_SUSPEND_INTERFACE)); if (!NT_SUCCESS(status)) goto fail2; + status = FdoQueryInterface(Fdo, + &GUID_XENBUS_STORE_INTERFACE, + XENBUS_STORE_INTERFACE_VERSION_MAX, + (PINTERFACE)&Fdo->StoreInterface, + sizeof(XENBUS_STORE_INTERFACE)); + if (!NT_SUCCESS(status)) + goto fail3; + + status = FdoQueryInterface(Fdo, + &GUID_XENHID_HID_INTERFACE, + XENHID_HID_INTERFACE_VERSION_MAX, + (PINTERFACE)&Fdo->HidInterface, + sizeof(XENHID_HID_INTERFACE)); + if (!NT_SUCCESS(status)) + goto fail4; + Trace("<=====\n"); return STATUS_SUCCESS; +fail4: + Error("fail4\n"); + + RtlZeroMemory(&Fdo->StoreInterface, + sizeof(XENBUS_STORE_INTERFACE)); + +fail3: + Error("fail3\n"); + + RtlZeroMemory(&Fdo->SuspendInterface, + sizeof(XENBUS_SUSPEND_INTERFACE)); + fail2: Error("fail2\n"); @@ -728,6 +1198,10 @@ FdoDestroy( RtlZeroMemory(&Fdo->HidInterface, sizeof(XENHID_HID_INTERFACE)); + RtlZeroMemory(&Fdo->SuspendInterface, + sizeof(XENBUS_SUSPEND_INTERFACE)); + RtlZeroMemory(&Fdo->StoreInterface, + sizeof(XENBUS_STORE_INTERFACE)); RtlZeroMemory(&Fdo->Queue, sizeof(IO_CSQ)); RtlZeroMemory(&Fdo->List, sizeof(LIST_ENTRY)); RtlZeroMemory(&Fdo->Lock, sizeof(KSPIN_LOCK)); diff --git a/src/xenhid/string.c b/src/xenhid/string.c new file mode 100644 index 0000000..7d2f1e3 --- /dev/null +++ b/src/xenhid/string.c @@ -0,0 +1,467 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#pragma warning(disable:4152) // nonstandard extension, function/data pointer conversion in expression + +#include <ntddk.h> + +#include "string.h" +#include "dbg_print.h" +#include "assert.h" + +static FORCEINLINE NTSTATUS +__StringPut( + IN PSTRING String, + IN CHAR Character + ) +{ + if (String->Length >= String->MaximumLength - 1) + return STATUS_BUFFER_OVERFLOW; + + String->Buffer[String->Length++] = Character; + return STATUS_SUCCESS; +} + +static PCHAR +FormatNumber( + IN PCHAR Buffer, + IN ULONGLONG Value, + IN UCHAR Base, + IN BOOLEAN UpperCase + ) +{ + ULONGLONG Next = Value / Base; + + if (Next != 0) + Buffer = FormatNumber(Buffer, Next, Base, UpperCase); + + Value %= Base; + + if (Value < 10) + *Buffer++ = '0' + (CHAR)Value; + else + *Buffer++ = ((UpperCase) ? 'A' : 'a') + (CHAR)(Value - 10); + + *Buffer = '\0'; + + return Buffer; +} + +#define FORMAT_NUMBER(_Arguments, _Type, _Character, _Buffer) \ + do { \ + U ## _Type _Value = va_arg((_Arguments), U ## _Type); \ + BOOLEAN _UpperCase = FALSE; \ + UCHAR _Base = 0; \ + ULONG _Index = 0; \ + \ + if ((_Character) == 'd' && (_Type)_Value < 0) { \ + _Value = -((_Type)_Value); \ + (_Buffer)[_Index++] = '-'; \ + } \ + \ + switch (_Character) { \ + case 'o': \ + _Base = 8; \ + break; \ + \ + case 'd': \ + case 'u': \ + _Base = 10; \ + break; \ + \ + case 'p': \ + case 'X': \ + _UpperCase = TRUE; \ + /* FALLTHRU */ \ + \ + case 'x': \ + _Base = 16; \ + break; \ + } \ + \ + (VOID) FormatNumber(&(_Buffer)[_Index], (ULONGLONG)_Value, _Base, _UpperCase); \ + } while (FALSE) + +static NTSTATUS +StringWriteBuffer( + IN PSTRING String, + IN const CHAR *Format, + IN va_list Arguments + ) +{ + CHAR Character; + NTSTATUS status; + + status = STATUS_SUCCESS; + + while ((Character = *Format++) != '\0') { + UCHAR Pad = 0; + UCHAR Long = 0; + BOOLEAN Wide = FALSE; + BOOLEAN ZeroPrefix = FALSE; + BOOLEAN OppositeJustification = FALSE; + + if (Character != '%') { + status = __StringPut(String, Character); + if (!NT_SUCCESS(status)) + goto done; + + continue; + } + + Character = *Format++; + ASSERT(Character != '\0'); + + if (Character == '-') { + OppositeJustification = TRUE; + Character = *Format++; + ASSERT(Character != '\0'); + } + + if (isdigit((unsigned char)Character)) { + ZeroPrefix = (Character == '0') ? TRUE : FALSE; + + while (isdigit((unsigned char)Character)) { + Pad = (Pad * 10) + (Character - '0'); + Character = *Format++; + ASSERT(Character != '\0'); + } + } + + while (Character == 'l') { + Long++; + Character = *Format++; + ASSERT(Character == 'd' || + Character == 'u' || + Character == 'o' || + Character == 'x' || + Character == 'X' || + Character == 'l'); + } + ASSERT3U(Long, <=, 2); + + while (Character == 'w') { + Wide = TRUE; + Character = *Format++; + ASSERT(Character == 'c' || + Character == 's' || + Character == 'Z'); + } + + switch (Character) { + case 'c': { + if (Wide) { + WCHAR Value; + Value = va_arg(Arguments, WCHAR); + + status = __StringPut(String, (CHAR)Value); + if (!NT_SUCCESS(status)) + goto done; + } else { + CHAR Value; + + Value = va_arg(Arguments, CHAR); + + status = __StringPut(String, Value); + if (!NT_SUCCESS(status)) + goto done; + } + break; + } + case 'p': + ZeroPrefix = TRUE; + Pad = sizeof (ULONG_PTR) * 2; + Long = sizeof (ULONG_PTR) / sizeof (ULONG); + /* FALLTHRU */ + + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': { + CHAR Buffer[23]; // Enough for 8 bytes in octal plus the NUL terminator + ULONG Length; + ULONG Index; + + if (Long == 2) + FORMAT_NUMBER(Arguments, LONGLONG, Character, Buffer); + else + FORMAT_NUMBER(Arguments, LONG, Character, Buffer); + + Length = (ULONG)strlen(Buffer); + if (!OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, (ZeroPrefix) ? '0' : ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + + for (Index = 0; Index < Length; Index++) { + status = __StringPut(String, Buffer[Index]); + if (!NT_SUCCESS(status)) + goto done; + } + + if (OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + + break; + } + case 's': { + if (Wide) { + PWCHAR Value = va_arg(Arguments, PWCHAR); + ULONG Length; + ULONG Index; + + if (Value == NULL) + Value = L"(null)"; + + Length = (ULONG)wcslen(Value); + + if (OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + + for (Index = 0; Index < Length; Index++) { + status = __StringPut(String, (CHAR)Value[Index]); + if (!NT_SUCCESS(status)) + goto done; + } + + if (!OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + } else { + PCHAR Value = va_arg(Arguments, PCHAR); + ULONG Length; + ULONG Index; + + if (Value == NULL) + Value = "(null)"; + + Length = (ULONG)strlen(Value); + + if (OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + + for (Index = 0; Index < Length; Index++) { + status = __StringPut(String, Value[Index]); + if (!NT_SUCCESS(status)) + goto done; + } + + if (!OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + } + + break; + } + case 'Z': { + if (Wide) { + PUNICODE_STRING Value = va_arg(Arguments, PUNICODE_STRING); + PWCHAR Buffer; + ULONG Length; + ULONG Index; + + if (Value == NULL) { + Buffer = L"(null)"; + Length = sizeof ("(null)") - 1; + } else { + Buffer = Value->Buffer; + Length = Value->Length / sizeof (WCHAR); + } + + if (OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + + for (Index = 0; Index < Length; Index++) { + status = __StringPut(String, (CHAR)Buffer[Index]); + if (!NT_SUCCESS(status)) + goto done; + } + + if (!OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + } else { + PANSI_STRING Value = va_arg(Arguments, PANSI_STRING); + PCHAR Buffer; + ULONG Length; + ULONG Index; + + if (Value == NULL) { + Buffer = "(null)"; + Length = sizeof ("(null)") - 1; + } else { + Buffer = Value->Buffer; + Length = Value->Length / sizeof (CHAR); + } + + if (OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + + for (Index = 0; Index < Length; Index++) { + status = __StringPut(String, Buffer[Index]); + if (!NT_SUCCESS(status)) + goto done; + } + + if (!OppositeJustification) { + while (Pad > Length) { + status = __StringPut(String, ' '); + if (!NT_SUCCESS(status)) + goto done; + + --Pad; + } + } + } + + break; + } + default: + status = __StringPut(String, Character); + if (!NT_SUCCESS(status)) + goto done; + + break; + } + } + +done: + return status; +} + +NTSTATUS +StringVPrintf( + IN PSTRING String, + IN const CHAR *Format, + IN va_list Arguments + ) +{ + NTSTATUS status; + + status = StringWriteBuffer(String, + Format, + Arguments); + if (!NT_SUCCESS(status)) + goto fail1; + + status = __StringPut(String, '\0'); + if (!NT_SUCCESS(status)) + goto fail2; + + // Length should not include the NUL terminator + --String->Length; + + return STATUS_SUCCESS; + +fail2: + Error("fail2\n"); + +fail1: + Error("fail1 (%08x)\n", status); + + return status; +} + +NTSTATUS +StringPrintf( + IN PSTRING String, + IN const CHAR *Format, + ... + ) +{ + va_list Arguments; + NTSTATUS status; + + va_start(Arguments, Format); + status = StringVPrintf(String, Format, Arguments); + va_end(Arguments); + + return status; +} diff --git a/src/xenhid/string.h b/src/xenhid/string.h new file mode 100644 index 0000000..389239e --- /dev/null +++ b/src/xenhid/string.h @@ -0,0 +1,51 @@ +/* Copyright (c) Citrix Systems Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, + * with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above + * copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _XENHID_STRING_H +#define _XENHID_STRING_H + +#include <ntddk.h> + +extern NTSTATUS +StringVPrintf( + IN PSTRING String, + IN const CHAR *Format, + IN va_list Arguments + ); + +extern NTSTATUS +StringPrintf( + IN PSTRING String, + IN const CHAR *Format, + ... + ); + +#endif // _XENHID_STRING_H diff --git a/vs2015/xenhid/xenhid.vcxproj b/vs2015/xenhid/xenhid.vcxproj index 3c2e27d..b0a84ea 100644 --- a/vs2015/xenhid/xenhid.vcxproj +++ b/vs2015/xenhid/xenhid.vcxproj @@ -66,6 +66,7 @@ <ItemGroup> <ClCompile Include="../../src/xenhid/driver.c" /> <ClCompile Include="../../src/xenhid/fdo.c" /> + <ClCompile Include="../../src/xenhid/string.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\src\xenhid\xenhid.rc" /> diff --git a/vs2017/xenhid/xenhid.vcxproj b/vs2017/xenhid/xenhid.vcxproj index 0872aa4..9c3d2b6 100644 --- a/vs2017/xenhid/xenhid.vcxproj +++ b/vs2017/xenhid/xenhid.vcxproj @@ -74,6 +74,7 @@ <ItemGroup> <ClCompile Include="../../src/xenhid/driver.c" /> <ClCompile Include="../../src/xenhid/fdo.c" /> + <ClCompile Include="../../src/xenhid/string.c" /> </ItemGroup> <ItemGroup> <ResourceCompile Include="..\..\src\xenhid\xenhid.rc" /> -- 2.16.2.windows.1 _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |