/* $Id: VBoxGuestLibSharedFoldersInline.h $ */
/** @file
 * VBoxGuestLib - Shared Folders Host Request Helpers (ring-0).
 */

/*
 * Copyright (C) 2006-2025 Oracle and/or its affiliates.
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

#ifndef VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h
#define VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h
#ifndef RT_WITHOUT_PRAGMA_ONCE
# pragma once
#endif

#include <iprt/types.h>
#include <iprt/assert.h>
#include <VBox/VBoxGuest.h>
#include <VBox/VBoxGuestLib.h>
#include <VBox/VBoxGuestLibSharedFolders.h>
#include <VBox/VMMDev.h>
#include <VBox/shflsvc.h>
#include <iprt/err.h>


/** @defgroup grp_vboxguest_lib_r0_sf_inline    Shared Folders Host Request Helpers
 * @ingroup grp_vboxguest_lib_r0
 *
 * @note Using inline functions to avoid wasting precious ring-0 stack space on
 *       passing parameters that ends up in the structure @a pReq points to.  It
 *       is also safe to assume that it's faster too.  It's worth a few bytes
 *       larger code section in the resulting shared folders driver.
 *
 * @note This currently requires a C++ compiler or a C compiler capable of
 *       mixing code and variables (i.e. C99).
 *
 * @{
 */

/** VMMDEV_HVF_XXX (set during init). */
extern uint32_t g_fHostFeatures;
extern VBGLSFCLIENT g_SfClient; /**< Move this into the parameters? */

/** Request structure for VbglR0SfHostReqQueryFeatures. */
typedef struct VBOXSFQUERYFEATURES
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmQueryFeatures Parms;
} VBOXSFQUERYFEATURES;

/**
 * SHFL_FN_QUERY_FEATURES request.
 */
DECLINLINE(int) VbglR0SfHostReqQueryFeatures(VBOXSFQUERYFEATURES *pReq)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_QUERY_FEATURES, SHFL_CPARMS_QUERY_FEATURES, sizeof(*pReq));

    pReq->Parms.f64Features.type          = VMMDevHGCMParmType_64bit;
    pReq->Parms.f64Features.u.value64     = 0;

    pReq->Parms.u32LastFunction.type      = VMMDevHGCMParmType_32bit;
    pReq->Parms.u32LastFunction.u.value32 = 0;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;

    /*
     * Provide fallback values based on g_fHostFeatures to simplify
     * compatibility with older hosts and avoid duplicating this logic.
     */
    if (RT_FAILURE(vrc))
    {
        pReq->Parms.f64Features.u.value64     = 0;
        pReq->Parms.u32LastFunction.u.value32 = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST
                                              ?  SHFL_FN_SET_FILE_SIZE : SHFL_FN_SET_SYMLINKS;
        if (vrc == VERR_NOT_SUPPORTED)
            vrc = VINF_NOT_SUPPORTED;
    }
    return vrc;
}

/**
 * SHFL_FN_QUERY_FEATURES request, simplified version.
 */
DECLINLINE(int) VbglR0SfHostReqQueryFeaturesSimple(uint64_t *pfFeatures, uint32_t *puLastFunction)
{
    VBOXSFQUERYFEATURES *pReq = (VBOXSFQUERYFEATURES *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int rc = VbglR0SfHostReqQueryFeatures(pReq);
        if (pfFeatures)
            *pfFeatures = pReq->Parms.f64Features.u.value64;
        if (puLastFunction)
            *puLastFunction = pReq->Parms.u32LastFunction.u.value32;

        VbglR0PhysHeapFree(pReq);
        return rc;
    }
    return VERR_NO_MEMORY;
}


/** Request structure for VbglR0SfHostReqSetUtf8 and VbglR0SfHostReqSetSymlink. */
typedef struct VBOXSFNOPARMS
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    /* no parameters */
} VBOXSFNOPARMS;

/**
 * Worker for request without any parameters.
 */
DECLINLINE(int) VbglR0SfHostReqNoParms(VBOXSFNOPARMS *pReq, uint32_t uFunction, uint32_t cParms)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                uFunction, cParms, sizeof(*pReq));
    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * Worker for request without any parameters, simplified.
 */
DECLINLINE(int) VbglR0SfHostReqNoParmsSimple(uint32_t uFunction, uint32_t cParms)
{
    VBOXSFNOPARMS *pReq = (VBOXSFNOPARMS *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int vrc = VbglR0SfHostReqNoParms(pReq, uFunction, cParms);
        VbglR0PhysHeapFree(pReq);
        return vrc;
    }
    return VERR_NO_MEMORY;
}


/**
 * SHFL_F_SET_UTF8 request.
 */
DECLINLINE(int) VbglR0SfHostReqSetUtf8(VBOXSFNOPARMS *pReq)
{
    return VbglR0SfHostReqNoParms(pReq, SHFL_FN_SET_UTF8, SHFL_CPARMS_SET_UTF8);
}

/**
 * SHFL_F_SET_UTF8 request, simplified version.
 */
DECLINLINE(int) VbglR0SfHostReqSetUtf8Simple(void)
{
    return VbglR0SfHostReqNoParmsSimple(SHFL_FN_SET_UTF8, SHFL_CPARMS_SET_UTF8);
}


/**
 * SHFL_F_SET_SYMLINKS request.
 */
DECLINLINE(int) VbglR0SfHostReqSetSymlinks(VBOXSFNOPARMS *pReq)
{
    return VbglR0SfHostReqNoParms(pReq, SHFL_FN_SET_SYMLINKS, SHFL_CPARMS_SET_SYMLINKS);
}

/**
 * SHFL_F_SET_SYMLINKS request, simplified version.
 */
DECLINLINE(int) VbglR0SfHostReqSetSymlinksSimple(void)
{
    return VbglR0SfHostReqNoParmsSimple(SHFL_FN_SET_SYMLINKS, SHFL_CPARMS_SET_SYMLINKS);
}


/** Request structure for VbglR0SfHostReqSetErrorStyle.  */
typedef struct VBOXSFSETERRORSTYLE
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmSetErrorStyle Parms;
} VBOXSFSETERRORSTYLE;

/**
 * SHFL_FN_QUERY_FEATURES request.
 */
DECLINLINE(int) VbglR0SfHostReqSetErrorStyle(VBOXSFSETERRORSTYLE *pReq, SHFLERRORSTYLE enmStyle)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_SET_ERROR_STYLE, SHFL_CPARMS_SET_ERROR_STYLE, sizeof(*pReq));

    pReq->Parms.u32Style.type           = VMMDevHGCMParmType_32bit;
    pReq->Parms.u32Style.u.value32      = (uint32_t)enmStyle;

    pReq->Parms.u32Reserved.type        = VMMDevHGCMParmType_32bit;
    pReq->Parms.u32Reserved.u.value32   = 0;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_QUERY_FEATURES request, simplified version.
 */
DECLINLINE(int) VbglR0SfHostReqSetErrorStyleSimple(SHFLERRORSTYLE enmStyle)
{
    VBOXSFSETERRORSTYLE *pReq = (VBOXSFSETERRORSTYLE *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int rc = VbglR0SfHostReqSetErrorStyle(pReq, enmStyle);
        VbglR0PhysHeapFree(pReq);
        return rc;
    }
    return VERR_NO_MEMORY;
}


/** Request structure for VbglR0SfHostReqMapFolderWithBuf.  */
typedef struct VBOXSFMAPFOLDERWITHBUFREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmMapFolder     Parms;
    HGCMPageListInfo        PgLst;
} VBOXSFMAPFOLDERWITHBUFREQ;


/**
 * SHFL_FN_MAP_FOLDER request.
 */
DECLINLINE(int) VbglR0SfHostReqMapFolderWithContig(VBOXSFMAPFOLDERWITHBUFREQ *pReq, PSHFLSTRING pStrName, RTGCPHYS64 PhysStrName,
                                                   RTUTF16 wcDelimiter, bool fCaseSensitive)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_MAP_FOLDER, SHFL_CPARMS_MAP_FOLDER, sizeof(*pReq));

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = SHFL_ROOT_NIL;

    pReq->Parms.uc32Delimiter.type              = VMMDevHGCMParmType_32bit;
    pReq->Parms.uc32Delimiter.u.value32         = wcDelimiter;

    pReq->Parms.fCaseSensitive.type             = VMMDevHGCMParmType_32bit;
    pReq->Parms.fCaseSensitive.u.value32        = fCaseSensitive;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
    {
        pReq->Parms.pStrName.type               = VMMDevHGCMParmType_PageList;
        pReq->Parms.pStrName.u.PageList.size    = SHFLSTRING_HEADER_SIZE + pStrName->u16Size;
        pReq->Parms.pStrName.u.PageList.offset  = RT_UOFFSETOF(VBOXSFMAPFOLDERWITHBUFREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLst.flags                       = VBOX_HGCM_F_PARM_DIRECTION_BOTH;
        pReq->PgLst.offFirstPage                = (uint16_t)PhysStrName & (uint16_t)(PAGE_OFFSET_MASK);
        pReq->PgLst.aPages[0]                   = PhysStrName & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
        pReq->PgLst.cPages                      = 1;
    }
    else
    {
        pReq->Parms.pStrName.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrName.u.LinAddr.cb       = SHFLSTRING_HEADER_SIZE + pStrName->u16Size;
        pReq->Parms.pStrName.u.LinAddr.uAddr    = (uintptr_t)pStrName;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_MAP_FOLDER request.
 */
DECLINLINE(int) VbglR0SfHostReqMapFolderWithContigSimple(PSHFLSTRING pStrName, RTGCPHYS64 PhysStrName,
                                                         RTUTF16 wcDelimiter, bool fCaseSensitive, SHFLROOT *pidRoot)
{
    VBOXSFMAPFOLDERWITHBUFREQ *pReq = (VBOXSFMAPFOLDERWITHBUFREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int rc = VbglR0SfHostReqMapFolderWithContig(pReq, pStrName, PhysStrName, wcDelimiter, fCaseSensitive);
        *pidRoot = RT_SUCCESS(rc) ? pReq->Parms.id32Root.u.value32 : SHFL_ROOT_NIL;
        VbglR0PhysHeapFree(pReq);
        return rc;
    }
    *pidRoot = SHFL_ROOT_NIL;
    return VERR_NO_MEMORY;
}


/**
 * SHFL_FN_MAP_FOLDER request.
 */
DECLINLINE(int) VbglR0SfHostReqMapFolderWithBuf(VBOXSFMAPFOLDERWITHBUFREQ *pReq, PSHFLSTRING pStrName,
                                                RTUTF16 wcDelimiter, bool fCaseSensitive)
{
    return VbglR0SfHostReqMapFolderWithContig(pReq, pStrName, VbglR0PhysHeapGetPhysAddr(pStrName), wcDelimiter, fCaseSensitive);
}



/** Request structure used by vboxSfOs2HostReqUnmapFolder.  */
typedef struct VBOXSFUNMAPFOLDERREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmUnmapFolder   Parms;
} VBOXSFUNMAPFOLDERREQ;


/**
 * SHFL_FN_UNMAP_FOLDER request.
 */
DECLINLINE(int) VbglR0SfHostReqUnmapFolderSimple(uint32_t idRoot)
{
    VBOXSFUNMAPFOLDERREQ *pReq = (VBOXSFUNMAPFOLDERREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        pReq->Parms.id32Root.type      = VMMDevHGCMParmType_32bit;
        pReq->Parms.id32Root.u.value32 = idRoot;

        VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                    SHFL_FN_UNMAP_FOLDER, SHFL_CPARMS_UNMAP_FOLDER, sizeof(*pReq));

        int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
        if (RT_SUCCESS(vrc))
            vrc = pReq->Call.header.result;

        VbglR0PhysHeapFree(pReq);
        return vrc;
    }
    return VERR_NO_MEMORY;
}


/** Request structure for VbglR0SfHostReqCreate.  */
typedef struct VBOXSFCREATEREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmCreate        Parms;
    SHFLCREATEPARMS         CreateParms;
    SHFLSTRING              StrPath;
} VBOXSFCREATEREQ;

/**
 * SHFL_FN_CREATE request.
 */
DECLINLINE(int) VbglR0SfHostReqCreate(SHFLROOT idRoot, VBOXSFCREATEREQ *pReq)
{
    uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                         ? RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + pReq->StrPath.u16Size
                         : RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_CREATE, SHFL_CPARMS_CREATE, cbReq);

    pReq->Parms.id32Root.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32                  = idRoot;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pStrPath.type                   = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pStrPath.u.Embedded.cbData      = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.Embedded.offData     = RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pStrPath.u.Embedded.fFlags      = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;

        pReq->Parms.pCreateParms.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pCreateParms.u.Embedded.cbData  = sizeof(pReq->CreateParms);
        pReq->Parms.pCreateParms.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pCreateParms.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_BOTH;
    }
    else
    {
        pReq->Parms.pStrPath.type                   = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrPath.u.LinAddr.cb           = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.LinAddr.uAddr        = (uintptr_t)&pReq->StrPath;

        pReq->Parms.pCreateParms.type               = VMMDevHGCMParmType_LinAddr;
        pReq->Parms.pCreateParms.u.LinAddr.cb       = sizeof(pReq->CreateParms);
        pReq->Parms.pCreateParms.u.LinAddr.uAddr    = (uintptr_t)&pReq->CreateParms;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqClose.  */
typedef struct VBOXSFCLOSEREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmClose         Parms;
} VBOXSFCLOSEREQ;

/**
 * SHFL_FN_CLOSE request.
 */
DECLINLINE(int) VbglR0SfHostReqClose(SHFLROOT idRoot, VBOXSFCLOSEREQ *pReq, uint64_t hHostFile)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_CLOSE, SHFL_CPARMS_CLOSE, sizeof(*pReq));

    pReq->Parms.id32Root.type       = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32  = idRoot;

    pReq->Parms.u64Handle.type      = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64 = hHostFile;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_CLOSE request, allocate request buffer.
 */
DECLINLINE(int) VbglR0SfHostReqCloseSimple(SHFLROOT idRoot, uint64_t hHostFile)
{
    VBOXSFCLOSEREQ *pReq = (VBOXSFCLOSEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int vrc = VbglR0SfHostReqClose(idRoot, pReq, hHostFile);
        VbglR0PhysHeapFree(pReq);
        return vrc;
    }
    return VERR_NO_MEMORY;
}


/** Request structure for VbglR0SfHostReqQueryVolInfo.  */
typedef struct VBOXSFVOLINFOREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmInformation   Parms;
    SHFLVOLINFO             VolInfo;
} VBOXSFVOLINFOREQ;

/**
 * SHFL_FN_INFORMATION[SHFL_INFO_VOLUME | SHFL_INFO_GET] request.
 */
DECLINLINE(int) VbglR0SfHostReqQueryVolInfo(SHFLROOT idRoot, VBOXSFVOLINFOREQ *pReq, uint64_t hHostFile)
{
    uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                         ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFVOLINFOREQ, VolInfo);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    pReq->Parms.u64Handle.type                  = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64             = hHostFile;

    pReq->Parms.f32Flags.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32              = SHFL_INFO_VOLUME | SHFL_INFO_GET;

    pReq->Parms.cb32.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32.u.value32                  = sizeof(pReq->VolInfo);

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pInfo.u.Embedded.cbData     = sizeof(pReq->VolInfo);
        pReq->Parms.pInfo.u.Embedded.offData    = RT_UOFFSETOF(VBOXSFVOLINFOREQ, VolInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pInfo.u.Embedded.fFlags     = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
    }
    else
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pInfo.u.LinAddr.cb          = sizeof(pReq->VolInfo);
        pReq->Parms.pInfo.u.LinAddr.uAddr       = (uintptr_t)&pReq->VolInfo;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqSetObjInfo & VbglR0SfHostReqQueryObjInfo. */
typedef struct VBOXSFOBJINFOREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmInformation   Parms;
    SHFLFSOBJINFO           ObjInfo;
} VBOXSFOBJINFOREQ;

/**
 * SHFL_FN_INFORMATION[SHFL_INFO_GET | SHFL_INFO_FILE] request.
 */
DECLINLINE(int) VbglR0SfHostReqQueryObjInfo(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile)
{
    uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                         ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    pReq->Parms.u64Handle.type                  = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64             = hHostFile;

    pReq->Parms.f32Flags.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32              = SHFL_INFO_GET | SHFL_INFO_FILE;

    pReq->Parms.cb32.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32.u.value32                  = sizeof(pReq->ObjInfo);

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pInfo.u.Embedded.cbData     = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.Embedded.offData    = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pInfo.u.Embedded.fFlags     = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
    }
    else
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pInfo.u.LinAddr.cb          = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.LinAddr.uAddr       = (uintptr_t)&pReq->ObjInfo;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/**
 * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_FILE] request.
 */
DECLINLINE(int) VbglR0SfHostReqSetObjInfo(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile)
{
    uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                         ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    pReq->Parms.u64Handle.type                  = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64             = hHostFile;

    pReq->Parms.f32Flags.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32              = SHFL_INFO_SET | SHFL_INFO_FILE;

    pReq->Parms.cb32.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32.u.value32                  = sizeof(pReq->ObjInfo);

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pInfo.u.Embedded.cbData     = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.Embedded.offData    = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pInfo.u.Embedded.fFlags     = VBOX_HGCM_F_PARM_DIRECTION_BOTH;
    }
    else
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_LinAddr;
        pReq->Parms.pInfo.u.LinAddr.cb          = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.LinAddr.uAddr       = (uintptr_t)&pReq->ObjInfo;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/**
 * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_SIZE] request.
 */
DECLINLINE(int) VbglR0SfHostReqSetFileSizeOld(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile)
{
    uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                         ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    pReq->Parms.u64Handle.type                  = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64             = hHostFile;

    pReq->Parms.f32Flags.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32              = SHFL_INFO_SET | SHFL_INFO_SIZE;

    pReq->Parms.cb32.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32.u.value32                  = sizeof(pReq->ObjInfo);

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pInfo.u.Embedded.cbData     = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.Embedded.offData    = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pInfo.u.Embedded.fFlags     = VBOX_HGCM_F_PARM_DIRECTION_BOTH;
    }
    else
    {
        pReq->Parms.pInfo.type                  = VMMDevHGCMParmType_LinAddr;
        pReq->Parms.pInfo.u.LinAddr.cb          = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.LinAddr.uAddr       = (uintptr_t)&pReq->ObjInfo;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqSetObjInfo.  */
typedef struct VBOXSFOBJINFOWITHBUFREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmInformation   Parms;
    HGCMPageListInfo        PgLst;
} VBOXSFOBJINFOWITHBUFREQ;

/**
 * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_FILE] request, with separate
 * buffer (on the physical heap).
 */
DECLINLINE(int) VbglR0SfHostReqSetObjInfoWithBuf(SHFLROOT idRoot, VBOXSFOBJINFOWITHBUFREQ *pReq, uint64_t hHostFile,
                                                 PSHFLFSOBJINFO pObjInfo, uint32_t offObjInfoInAlloc)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq));

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.f32Flags.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32          = SHFL_INFO_SET | SHFL_INFO_FILE;

    pReq->Parms.cb32.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32.u.value32              = sizeof(*pObjInfo);

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
    {
        pReq->Parms.pInfo.type              = VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pInfo.u.PageList.size   = sizeof(*pObjInfo);
        pReq->Parms.pInfo.u.PageList.offset = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLst.flags                   = VBOX_HGCM_F_PARM_DIRECTION_BOTH;
        pReq->PgLst.aPages[0]               = VbglR0PhysHeapGetPhysAddr((uint8_t *)pObjInfo - offObjInfoInAlloc) + offObjInfoInAlloc;
        pReq->PgLst.offFirstPage            = (uint16_t)(pReq->PgLst.aPages[0] & PAGE_OFFSET_MASK);
        pReq->PgLst.aPages[0]              &= ~(RTGCPHYS)PAGE_OFFSET_MASK;
        pReq->PgLst.cPages                  = 1;
    }
    else
    {
        pReq->Parms.pInfo.type              = VMMDevHGCMParmType_LinAddr;
        pReq->Parms.pInfo.u.LinAddr.cb      = sizeof(*pObjInfo);
        pReq->Parms.pInfo.u.LinAddr.uAddr   = (uintptr_t)pObjInfo;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqRemove.  */
typedef struct VBOXSFREMOVEREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmRemove        Parms;
    SHFLSTRING              StrPath;
} VBOXSFREMOVEREQ;

/**
 * SHFL_FN_REMOVE request.
 */
DECLINLINE(int) VbglR0SfHostReqRemove(SHFLROOT idRoot, VBOXSFREMOVEREQ *pReq, uint32_t fFlags)
{
    uint32_t const cbReq = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String)
                         + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrPath.u16Size : 0);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_REMOVE, SHFL_CPARMS_REMOVE, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pStrPath.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pStrPath.u.Embedded.cbData  = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pStrPath.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    }
    else
    {
        pReq->Parms.pStrPath.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrPath.u.LinAddr.cb       = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.LinAddr.uAddr    = (uintptr_t)&pReq->StrPath;
    }

    pReq->Parms.f32Flags.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32              = fFlags;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqCloseAndRemove.  */
typedef struct VBOXSFCLOSEANDREMOVEREQ
{
    VBGLIOCIDCHGCMFASTCALL      Hdr;
    VMMDevHGCMCall              Call;
    VBoxSFParmCloseAndRemove    Parms;
    SHFLSTRING                  StrPath;
} VBOXSFCLOSEANDREMOVEREQ;

/**
 * SHFL_FN_CLOSE_AND_REMOVE request.
 */
DECLINLINE(int) VbglR0SfHostReqCloseAndRemove(SHFLROOT idRoot, VBOXSFCLOSEANDREMOVEREQ *pReq, uint32_t fFlags, SHFLHANDLE hToClose)
{
    uint32_t const cbReq = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath.String)
                         + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrPath.u16Size : 0);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_CLOSE_AND_REMOVE, SHFL_CPARMS_CLOSE_AND_REMOVE, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pStrPath.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pStrPath.u.Embedded.cbData  = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pStrPath.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    }
    else
    {
        pReq->Parms.pStrPath.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrPath.u.LinAddr.cb       = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.LinAddr.uAddr    = (uintptr_t)&pReq->StrPath;
    }

    pReq->Parms.f32Flags.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32              = fFlags;

    pReq->Parms.u64Handle.type                  = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64             = hToClose;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqRenameWithSrcContig and
 *  VbglR0SfHostReqRenameWithSrcBuf. */
typedef struct VBOXSFRENAMEWITHSRCBUFREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmRename        Parms;
    HGCMPageListInfo        PgLst;
    SHFLSTRING              StrDstPath;
} VBOXSFRENAMEWITHSRCBUFREQ;


/**
 * SHFL_FN_REMOVE request.
 */
DECLINLINE(int) VbglR0SfHostReqRenameWithSrcContig(SHFLROOT idRoot, VBOXSFRENAMEWITHSRCBUFREQ *pReq,
                                                   PSHFLSTRING pSrcStr, RTGCPHYS64 PhysSrcStr, uint32_t fFlags)
{
    uint32_t const cbReq = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String)
                         + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrDstPath.u16Size : 0);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_RENAME, SHFL_CPARMS_RENAME, cbReq);

    pReq->Parms.id32Root.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32                  = idRoot;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
    {
        pReq->Parms.pStrSrcPath.type                = VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pStrSrcPath.u.PageList.size     = SHFLSTRING_HEADER_SIZE + pSrcStr->u16Size;
        pReq->Parms.pStrSrcPath.u.PageList.offset   = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, PgLst)
                                                    - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLst.flags                           = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
        pReq->PgLst.offFirstPage                    = (uint16_t)PhysSrcStr & (uint16_t)(PAGE_OFFSET_MASK);
        pReq->PgLst.aPages[0]                       = PhysSrcStr & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
        pReq->PgLst.cPages                          = 1;
    }
    else
    {
        pReq->Parms.pStrSrcPath.type                = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrSrcPath.u.LinAddr.cb        = SHFLSTRING_HEADER_SIZE + pSrcStr->u16Size;
        pReq->Parms.pStrSrcPath.u.LinAddr.uAddr     = (uintptr_t)pSrcStr;
    }

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pStrDstPath.type                = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pStrDstPath.u.Embedded.cbData   = SHFLSTRING_HEADER_SIZE + pReq->StrDstPath.u16Size;
        pReq->Parms.pStrDstPath.u.Embedded.offData  = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath)
                                                    - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pStrDstPath.u.Embedded.fFlags   = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    }
    else
    {
        pReq->Parms.pStrDstPath.type                = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrDstPath.u.LinAddr.cb        = SHFLSTRING_HEADER_SIZE + pReq->StrDstPath.u16Size;
        pReq->Parms.pStrDstPath.u.LinAddr.uAddr     = (uintptr_t)&pReq->StrDstPath;
    }

    pReq->Parms.f32Flags.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32                  = fFlags;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/**
 * SHFL_FN_REMOVE request.
 */
DECLINLINE(int) VbglR0SfHostReqRenameWithSrcBuf(SHFLROOT idRoot, VBOXSFRENAMEWITHSRCBUFREQ *pReq,
                                                PSHFLSTRING pSrcStr, uint32_t fFlags)
{
    return VbglR0SfHostReqRenameWithSrcContig(idRoot, pReq, pSrcStr, VbglR0PhysHeapGetPhysAddr(pSrcStr), fFlags);
}


/** Request structure for VbglR0SfHostReqFlush.  */
typedef struct VBOXSFFLUSHREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmFlush         Parms;
} VBOXSFFLUSHREQ;

/**
 * SHFL_FN_FLUSH request.
 */
DECLINLINE(int) VbglR0SfHostReqFlush(SHFLROOT idRoot, VBOXSFFLUSHREQ *pReq, uint64_t hHostFile)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_FLUSH, SHFL_CPARMS_FLUSH, sizeof(*pReq));

    pReq->Parms.id32Root.type       = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32  = idRoot;

    pReq->Parms.u64Handle.type      = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64 = hHostFile;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_FLUSH request, allocate request buffer.
 */
DECLINLINE(int) VbglR0SfHostReqFlushSimple(SHFLROOT idRoot, uint64_t hHostFile)
{
    VBOXSFFLUSHREQ *pReq = (VBOXSFFLUSHREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int vrc = VbglR0SfHostReqFlush(idRoot, pReq, hHostFile);
        VbglR0PhysHeapFree(pReq);
        return vrc;
    }
    return VERR_NO_MEMORY;
}


/** Request structure for VbglR0SfHostReqSetFileSize.  */
typedef struct VBOXSFSETFILESIZEREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmSetFileSize   Parms;
} VBOXSFSETFILESIZEREQ;

/**
 * SHFL_FN_SET_FILE_SIZE request.
 */
DECLINLINE(int) VbglR0SfHostReqSetFileSize(SHFLROOT idRoot, VBOXSFSETFILESIZEREQ *pReq, uint64_t hHostFile, uint64_t cbNewSize)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_SET_FILE_SIZE, SHFL_CPARMS_SET_FILE_SIZE, sizeof(*pReq));

    pReq->Parms.id32Root.type           = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32      = idRoot;

    pReq->Parms.u64Handle.type          = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64     = hHostFile;

    pReq->Parms.cb64NewSize.type        = VMMDevHGCMParmType_64bit;
    pReq->Parms.cb64NewSize.u.value64   = cbNewSize;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_SET_FILE_SIZE request, allocate request buffer.
 */
DECLINLINE(int) VbglR0SfHostReqSetFileSizeSimple(SHFLROOT idRoot, uint64_t hHostFile, uint64_t cbNewSize)
{
    VBOXSFSETFILESIZEREQ *pReq = (VBOXSFSETFILESIZEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq));
    if (pReq)
    {
        int vrc = VbglR0SfHostReqSetFileSize(idRoot, pReq, hHostFile, cbNewSize);
        VbglR0PhysHeapFree(pReq);
        return vrc;
    }
    return VERR_NO_MEMORY;
}


/** Request structure for VbglR0SfHostReqReadEmbedded. */
typedef struct VBOXSFREADEMBEDDEDREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmRead          Parms;
    RT_FLEXIBLE_ARRAY_EXTENSION
    uint8_t                 abData[RT_FLEXIBLE_ARRAY];
} VBOXSFREADEMBEDDEDREQ;

/**
 * SHFL_FN_READ request using embedded data buffer.
 */
DECLINLINE(int) VbglR0SfHostReqReadEmbedded(SHFLROOT idRoot, VBOXSFREADEMBEDDEDREQ *pReq, uint64_t hHostFile,
                                            uint64_t offRead, uint32_t cbToRead)
{
    uint32_t const cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0])
                         + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? cbToRead : 0);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_READ, SHFL_CPARMS_READ, cbReq);

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.off64Read.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Read.u.value64         = offRead;

    pReq->Parms.cb32Read.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Read.u.value32          = cbToRead;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pBuf.u.Embedded.cbData  = cbToRead;
        pReq->Parms.pBuf.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pBuf.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
    }
    else
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pBuf.u.LinAddr.cb       = cbToRead;
        pReq->Parms.pBuf.u.LinAddr.uAddr    = (uintptr_t)&pReq->abData[0];
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for vboxSfOs2HostReqRead & VbglR0SfHostReqReadContig. */
typedef struct VBOXSFREADPGLSTREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmRead          Parms;
    HGCMPageListInfo        PgLst;
} VBOXSFREADPGLSTREQ;

/**
 * SHFL_FN_READ request using page list for data buffer (caller populated).
 */
DECLINLINE(int) VbglR0SfHostReqReadPgLst(SHFLROOT idRoot, VBOXSFREADPGLSTREQ *pReq, uint64_t hHostFile,
                                         uint64_t offRead, uint32_t cbToRead, uint32_t cPages)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_READ, SHFL_CPARMS_READ,
                                RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages]));

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.off64Read.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Read.u.value64         = offRead;

    pReq->Parms.cb32Read.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Read.u.value32          = cbToRead;

    pReq->Parms.pBuf.type                   = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST
                                            ? VMMDevHGCMParmType_NoBouncePageList : VMMDevHGCMParmType_PageList;
    pReq->Parms.pBuf.u.PageList.size        = cbToRead;
    pReq->Parms.pBuf.u.PageList.offset      = RT_UOFFSETOF(VBOXSFREADPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
    pReq->PgLst.flags                       = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
    pReq->PgLst.cPages                      = (uint16_t)cPages;
    AssertReturn(cPages <= UINT16_MAX, VERR_OUT_OF_RANGE);
    /* caller sets offset */

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr,
                                 RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages]));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/**
 * SHFL_FN_READ request using a physically contiguous buffer.
 */
DECLINLINE(int) VbglR0SfHostReqReadContig(SHFLROOT idRoot, VBOXSFREADPGLSTREQ *pReq, uint64_t hHostFile,
                                          uint64_t offRead, uint32_t cbToRead, void *pvBuffer, RTGCPHYS64 PhysBuffer)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_READ, SHFL_CPARMS_READ, RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[1]));

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.off64Read.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Read.u.value64         = offRead;

    pReq->Parms.cb32Read.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Read.u.value32          = cbToRead;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pBuf.u.PageList.size    = cbToRead;
        pReq->Parms.pBuf.u.PageList.offset  = RT_UOFFSETOF(VBOXSFREADPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLst.flags                   = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
        pReq->PgLst.offFirstPage            = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK);
        pReq->PgLst.cPages                  = 1;
        pReq->PgLst.aPages[0]               = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
    }
    else
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pBuf.u.LinAddr.cb       = cbToRead;
        pReq->Parms.pBuf.u.LinAddr.uAddr    = (uintptr_t)pvBuffer;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[1]));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}



/** Request structure for VbglR0SfHostReqWriteEmbedded. */
typedef struct VBOXSFWRITEEMBEDDEDREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmWrite         Parms;
    RT_FLEXIBLE_ARRAY_EXTENSION
    uint8_t                 abData[RT_FLEXIBLE_ARRAY];
} VBOXSFWRITEEMBEDDEDREQ;

/**
 * SHFL_FN_WRITE request using embedded data buffer.
 */
DECLINLINE(int) VbglR0SfHostReqWriteEmbedded(SHFLROOT idRoot, VBOXSFWRITEEMBEDDEDREQ *pReq, uint64_t hHostFile,
                                             uint64_t offWrite, uint32_t cbToWrite)
{
    uint32_t const cbReq = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0])
                         + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? cbToWrite : 0);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_WRITE, SHFL_CPARMS_WRITE, cbReq);

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.off64Write.type             = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Write.u.value64        = offWrite;

    pReq->Parms.cb32Write.type              = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Write.u.value32         = cbToWrite;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pBuf.u.Embedded.cbData  = cbToWrite;
        pReq->Parms.pBuf.u.Embedded.offData = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pBuf.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    }
    else
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pBuf.u.LinAddr.cb       = cbToWrite;
        pReq->Parms.pBuf.u.LinAddr.uAddr    = (uintptr_t)&pReq->abData[0];
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for vboxSfOs2HostReqWrite and VbglR0SfHostReqWriteContig. */
typedef struct VBOXSFWRITEPGLSTREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmWrite         Parms;
    HGCMPageListInfo        PgLst;
} VBOXSFWRITEPGLSTREQ;

/**
 * SHFL_FN_WRITE request using page list for data buffer (caller populated).
 */
DECLINLINE(int) VbglR0SfHostReqWritePgLst(SHFLROOT idRoot, VBOXSFWRITEPGLSTREQ *pReq, uint64_t hHostFile,
                                          uint64_t offWrite, uint32_t cbToWrite, uint32_t cPages)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_WRITE, SHFL_CPARMS_WRITE,
                                RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages]));

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.off64Write.type             = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Write.u.value64        = offWrite;

    pReq->Parms.cb32Write.type              = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Write.u.value32         = cbToWrite;

    pReq->Parms.pBuf.type                   = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST
                                            ? VMMDevHGCMParmType_NoBouncePageList : VMMDevHGCMParmType_PageList;;
    pReq->Parms.pBuf.u.PageList.size        = cbToWrite;
    pReq->Parms.pBuf.u.PageList.offset      = RT_UOFFSETOF(VBOXSFWRITEPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
    pReq->PgLst.flags                       = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    pReq->PgLst.cPages                      = (uint16_t)cPages;
    AssertReturn(cPages <= UINT16_MAX, VERR_OUT_OF_RANGE);
    /* caller sets offset */

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr,
                                 RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages]));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/**
 * SHFL_FN_WRITE request using a physically contiguous buffer.
 */
DECLINLINE(int) VbglR0SfHostReqWriteContig(SHFLROOT idRoot, VBOXSFWRITEPGLSTREQ *pReq, uint64_t hHostFile,
                                           uint64_t offWrite, uint32_t cbToWrite, void const *pvBuffer, RTGCPHYS64 PhysBuffer)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_WRITE, SHFL_CPARMS_WRITE, RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[1]));

    pReq->Parms.id32Root.type               = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32          = idRoot;

    pReq->Parms.u64Handle.type              = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64         = hHostFile;

    pReq->Parms.off64Write.type             = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Write.u.value64        = offWrite;

    pReq->Parms.cb32Write.type              = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Write.u.value32         = cbToWrite;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pBuf.u.PageList.size    = cbToWrite;
        pReq->Parms.pBuf.u.PageList.offset  = RT_UOFFSETOF(VBOXSFWRITEPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLst.flags                   = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
        pReq->PgLst.offFirstPage            = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK);
        pReq->PgLst.cPages                  = 1;
        pReq->PgLst.aPages[0]               = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
    }
    else
    {
        pReq->Parms.pBuf.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pBuf.u.LinAddr.cb       = cbToWrite;
        pReq->Parms.pBuf.u.LinAddr.uAddr    = (uintptr_t)pvBuffer;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[1]));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}


/** Request structure for VbglR0SfHostReqCopyFilePart.  */
typedef struct VBOXSFCOPYFILEPARTREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmCopyFilePart  Parms;
} VBOXSFCOPYFILEPARTREQ;

/**
 * SHFL_FN_CREATE request.
 */
DECLINLINE(int) VbglR0SfHostReqCopyFilePart(SHFLROOT idRootSrc, SHFLHANDLE hHostFileSrc, uint64_t offSrc,
                                            SHFLROOT idRootDst, SHFLHANDLE hHostFileDst, uint64_t offDst,
                                            uint64_t cbToCopy, uint32_t fFlags, VBOXSFCOPYFILEPARTREQ *pReq)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_COPY_FILE_PART, SHFL_CPARMS_COPY_FILE_PART, sizeof(*pReq));

    pReq->Parms.id32RootSrc.type        = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32RootSrc.u.value32   = idRootSrc;

    pReq->Parms.u64HandleSrc.type       = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64HandleSrc.u.value64  = hHostFileSrc;

    pReq->Parms.off64Src.type           = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Src.u.value64      = offSrc;

    pReq->Parms.id32RootDst.type        = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32RootDst.u.value32   = idRootDst;

    pReq->Parms.u64HandleDst.type       = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64HandleDst.u.value64  = hHostFileDst;

    pReq->Parms.off64Dst.type           = VMMDevHGCMParmType_64bit;
    pReq->Parms.off64Dst.u.value64      = offDst;

    pReq->Parms.cb64ToCopy.type         = VMMDevHGCMParmType_64bit;
    pReq->Parms.cb64ToCopy.u.value64    = cbToCopy;

    pReq->Parms.f32Flags.type           = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32      = fFlags;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}



/** Request structure for VbglR0SfHostReqListDirContig2x() and
 *  VbglR0SfHostReqListDir(). */
typedef struct VBOXSFLISTDIRREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmList          Parms;
    HGCMPageListInfo        StrPgLst;
    HGCMPageListInfo        BufPgLst;
} VBOXSFLISTDIRREQ;

/**
 * SHFL_FN_LIST request with separate string buffer and buffers for entries,
 * both physically contiguous allocations.
 */
DECLINLINE(int) VbglR0SfHostReqListDirContig2x(SHFLROOT idRoot, VBOXSFLISTDIRREQ *pReq, uint64_t hHostDir,
                                               PSHFLSTRING pFilter, RTGCPHYS64 PhysFilter, uint32_t fFlags,
                                               PSHFLDIRINFO pBuffer, RTGCPHYS64 PhysBuffer, uint32_t cbBuffer)
{
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_LIST, SHFL_CPARMS_LIST, sizeof(*pReq));

    pReq->Parms.id32Root.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32                  = idRoot;

    pReq->Parms.u64Handle.type                      = VMMDevHGCMParmType_64bit;
    pReq->Parms.u64Handle.u.value64                 = hHostDir;

    pReq->Parms.f32Flags.type                       = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32Flags.u.value32                  = fFlags;

    pReq->Parms.cb32Buffer.type                     = VMMDevHGCMParmType_32bit;
    pReq->Parms.cb32Buffer.u.value32                = cbBuffer;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
    {
        pReq->Parms.pStrFilter.type                 = VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pStrFilter.u.PageList.offset    = RT_UOFFSETOF(VBOXSFLISTDIRREQ, StrPgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->StrPgLst.flags                        = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
        pReq->StrPgLst.cPages                       = 1;
        if (pFilter)
        {
            pReq->Parms.pStrFilter.u.PageList.size  = SHFLSTRING_HEADER_SIZE + pFilter->u16Size;
            uint32_t const offFirstPage = (uint32_t)PhysFilter & PAGE_OFFSET_MASK;
            pReq->StrPgLst.offFirstPage             = (uint16_t)offFirstPage;
            pReq->StrPgLst.aPages[0]                = PhysFilter - offFirstPage;
        }
        else
        {
            pReq->Parms.pStrFilter.u.PageList.size  = 0;
            pReq->StrPgLst.offFirstPage             = 0;
            pReq->StrPgLst.aPages[0]                = NIL_RTGCPHYS64;
        }

        pReq->Parms.pBuffer.type                    = VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pBuffer.u.PageList.offset       = RT_UOFFSETOF(VBOXSFLISTDIRREQ, BufPgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pBuffer.u.PageList.size         = cbBuffer;
        pReq->BufPgLst.flags                        = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
        pReq->BufPgLst.cPages                       = 1;
        uint32_t const offFirstPage = (uint32_t)PhysBuffer & PAGE_OFFSET_MASK;
        pReq->BufPgLst.offFirstPage                 = (uint16_t)offFirstPage;
        pReq->BufPgLst.aPages[0]                    = PhysBuffer - offFirstPage;
    }
    else
    {
        pReq->Parms.pStrFilter.type                 = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrFilter.u.LinAddr.cb         = pFilter ? SHFLSTRING_HEADER_SIZE + pFilter->u16Size : 0;
        pReq->Parms.pStrFilter.u.LinAddr.uAddr      = (uintptr_t)pFilter;

        pReq->Parms.pBuffer.type                    = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pBuffer.u.LinAddr.cb            = cbBuffer;
        pReq->Parms.pBuffer.u.LinAddr.uAddr         = (uintptr_t)pBuffer;
    }

    pReq->Parms.f32More.type                        = VMMDevHGCMParmType_32bit;
    pReq->Parms.f32More.u.value32                   = 0;

    pReq->Parms.c32Entries.type                     = VMMDevHGCMParmType_32bit;
    pReq->Parms.c32Entries.u.value32                = 0;

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq));
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_LIST request with separate string buffer and buffers for entries,
 * both allocated on the physical heap.
 */
DECLINLINE(int) VbglR0SfHostReqListDir(SHFLROOT idRoot, VBOXSFLISTDIRREQ *pReq, uint64_t hHostDir,
                                       PSHFLSTRING pFilter, uint32_t fFlags, PSHFLDIRINFO pBuffer, uint32_t cbBuffer)
{
    return VbglR0SfHostReqListDirContig2x(idRoot,
                                          pReq,
                                          hHostDir,
                                          pFilter,
                                          pFilter ? VbglR0PhysHeapGetPhysAddr(pFilter) : NIL_RTGCPHYS64,
                                          fFlags,
                                          pBuffer,
                                          VbglR0PhysHeapGetPhysAddr(pBuffer),
                                          cbBuffer);
}


/** Request structure for VbglR0SfHostReqReadLink.  */
typedef struct VBOXSFREADLINKREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmReadLink      Parms;
    HGCMPageListInfo        PgLst;
    SHFLSTRING              StrPath;
} VBOXSFREADLINKREQ;

/**
 * SHFL_FN_READLINK request.
 *
 * @note Buffer contains UTF-8 characters on success, regardless of the
 *       UTF-8/UTF-16 setting of the connection.
 */
DECLINLINE(int) VbglR0SfHostReqReadLinkContig(SHFLROOT idRoot, void *pvBuffer, RTGCPHYS64 PhysBuffer, uint32_t cbBuffer,
                                              VBOXSFREADLINKREQ *pReq)
{
    uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                         ? RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + pReq->StrPath.u16Size
                         :    cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK)
                           || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)
                         ? RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String)
                         : RT_UOFFSETOF(VBOXSFREADLINKREQ, PgLst);
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_READLINK, SHFL_CPARMS_READLINK, cbReq);

    pReq->Parms.id32Root.type                   = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32              = idRoot;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pStrPath.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pStrPath.u.Embedded.cbData  = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath)
                                                - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pStrPath.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    }
    else
    {
        pReq->Parms.pStrPath.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrPath.u.LinAddr.cb       = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size;
        pReq->Parms.pStrPath.u.LinAddr.uAddr    = (uintptr_t)&pReq->StrPath;
    }

    if (   cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK)
        || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST))
    {
        pReq->Parms.pBuffer.type                = cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK)
                                                ? VMMDevHGCMParmType_PageList
                                                : VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pBuffer.u.PageList.size     = cbBuffer;
        pReq->Parms.pBuffer.u.PageList.offset   = RT_UOFFSETOF(VBOXSFREADLINKREQ, PgLst)
                                                - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLst.flags                       = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
        pReq->PgLst.offFirstPage                = (uint16_t)PhysBuffer & (uint16_t)(PAGE_OFFSET_MASK);
        pReq->PgLst.aPages[0]                   = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
        pReq->PgLst.cPages                      = 1;
    }
    else
    {
        pReq->Parms.pBuffer.type                = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pBuffer.u.LinAddr.cb        = cbBuffer;
        pReq->Parms.pBuffer.u.LinAddr.uAddr     = (uintptr_t)pvBuffer;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/**
 * SHFL_FN_READLINK request, simplified version.
 *
 *
 * @note Buffer contains UTF-8 characters on success, regardless of the
 *       UTF-8/UTF-16 setting of the connection.
 */
DECLINLINE(int) VbglR0SfHostReqReadLinkContigSimple(SHFLROOT idRoot, const char *pszPath, size_t cchPath, void *pvBuf,
                                                    RTGCPHYS64 PhysBuffer, uint32_t cbBuffer)
{
    if (cchPath < _64K - 1)
    {
        VBOXSFREADLINKREQ *pReq = (VBOXSFREADLINKREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String)
                                                                           + SHFLSTRING_HEADER_SIZE + (uint32_t)cchPath);
        if (pReq)
        {
            char * const pszReqPath = pReq->StrPath.String.ach;
            pReq->StrPath.u16Length = (uint16_t)cchPath;
            pReq->StrPath.u16Size   = (uint16_t)cchPath + 1;
            RT_BCOPY_UNFORTIFIED(pszReqPath, pszPath, cchPath);
            pszReqPath[cchPath] = '\0';

            {
                int vrc = VbglR0SfHostReqReadLinkContig(idRoot, pvBuf, PhysBuffer, cbBuffer, pReq);
                VbglR0PhysHeapFree(pReq);
                return vrc;
            }
        }
        return VERR_NO_MEMORY;
    }
    return VERR_FILENAME_TOO_LONG;
}


/** Request structure for VbglR0SfHostReqCreateSymlink.  */
typedef struct VBOXSFCREATESYMLINKREQ
{
    VBGLIOCIDCHGCMFASTCALL  Hdr;
    VMMDevHGCMCall          Call;
    VBoxSFParmCreateSymlink Parms;
    HGCMPageListInfo        PgLstTarget;
    SHFLFSOBJINFO           ObjInfo;
    SHFLSTRING              StrSymlinkPath;
} VBOXSFCREATESYMLINKREQ;

/**
 * SHFL_FN_SYMLINK request.
 *
 * Caller fills in the symlink string and supplies a physical contiguous
 * target string
 */
DECLINLINE(int) VbglR0SfHostReqCreateSymlinkContig(SHFLROOT idRoot, PCSHFLSTRING pStrTarget, RTGCPHYS64 PhysTarget,
                                                   VBOXSFCREATESYMLINKREQ *pReq)
{
    uint32_t const cbTarget = SHFLSTRING_HEADER_SIZE + pStrTarget->u16Size;
    uint32_t const cbReq    = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS
                            ? RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath.String) + pReq->StrSymlinkPath.u16Size
                            : RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, ObjInfo) /*simplified*/;
    VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient,
                                SHFL_FN_SYMLINK, SHFL_CPARMS_SYMLINK, cbReq);

    pReq->Parms.id32Root.type                          = VMMDevHGCMParmType_32bit;
    pReq->Parms.id32Root.u.value32                     = idRoot;

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pStrSymlink.type               = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pStrSymlink.u.Embedded.cbData  = SHFLSTRING_HEADER_SIZE + pReq->StrSymlinkPath.u16Size;
        pReq->Parms.pStrSymlink.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath)
                                                   - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pStrSymlink.u.Embedded.fFlags  = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
    }
    else
    {
        pReq->Parms.pStrSymlink.type               = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrSymlink.u.LinAddr.cb       = SHFLSTRING_HEADER_SIZE + pReq->StrSymlinkPath.u16Size;
        pReq->Parms.pStrSymlink.u.LinAddr.uAddr    = (uintptr_t)&pReq->StrSymlinkPath;
    }

    if (   cbTarget <= PAGE_SIZE - (PhysTarget & PAGE_OFFSET_MASK)
        || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST))
    {
        pReq->Parms.pStrTarget.type                = cbTarget <= PAGE_SIZE - (PhysTarget & PAGE_OFFSET_MASK)
                                                   ? VMMDevHGCMParmType_PageList
                                                   : VMMDevHGCMParmType_ContiguousPageList;
        pReq->Parms.pStrTarget.u.PageList.size     = cbTarget;
        pReq->Parms.pStrTarget.u.PageList.offset   = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, PgLstTarget)
                                                   - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->PgLstTarget.flags                    = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST;
        pReq->PgLstTarget.offFirstPage             = (uint16_t)PhysTarget & (uint16_t)(PAGE_OFFSET_MASK);
        pReq->PgLstTarget.aPages[0]                = PhysTarget & ~(RTGCPHYS64)PAGE_OFFSET_MASK;
        pReq->PgLstTarget.cPages                   = 1;
    }
    else
    {
        pReq->Parms.pStrTarget.type                = VMMDevHGCMParmType_LinAddr_In;
        pReq->Parms.pStrTarget.u.LinAddr.cb        = cbTarget;
        pReq->Parms.pStrTarget.u.LinAddr.uAddr     = (uintptr_t)pStrTarget;
    }

    if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS)
    {
        pReq->Parms.pInfo.type                     = VMMDevHGCMParmType_Embedded;
        pReq->Parms.pInfo.u.Embedded.cbData        = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.Embedded.offData       = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, ObjInfo)
                                                   - sizeof(VBGLIOCIDCHGCMFASTCALL);
        pReq->Parms.pInfo.u.Embedded.fFlags        = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST;
    }
    else
    {
        pReq->Parms.pInfo.type                     = VMMDevHGCMParmType_LinAddr_Out;
        pReq->Parms.pInfo.u.LinAddr.cb             = sizeof(pReq->ObjInfo);
        pReq->Parms.pInfo.u.LinAddr.uAddr          = (uintptr_t)&pReq->ObjInfo;
    }

    int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq);
    if (RT_SUCCESS(vrc))
        vrc = pReq->Call.header.result;
    return vrc;
}

/** @} */

#endif /* !VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h */

