/*++

Copyright (c) 1991-92  Microsoft Corporation

Module Name:

    rxshare.c

Abstract:

    Contains down-level remoted RxNetShare routines:
        RxNetShareAdd
        RxNetShareCheck
        RxNetShareDel
        RxNetShareEnum
        RxNetShareGetInfo
        RxNetShareSetInfo
        (GetShareInfoDescriptors)
        (ConvertMaxUsesField)

Author:

    Richard Firth (rfirth) 20-May-1991

Environment:

    Win-32/flat address space

Notes:

    Routines in this module assume that caller-supplied parameters have
    already been verified. No effort is made to further check the veracity
    of parms. Any actions causing exceptions must be trapped at a higher
    level. This applies to ALL parameters - strings, pointers, buffers, etc.

Revision History:

    08-Apr-1992
        Try to avoid >1 calls to down-level server for RxNetShareEnum
        Fix problem of converting 16-bit numbers >32768 into negative 32-bit
        numbers on GetInfo and Enum: 65535 is a special value; everything
        else in unsigned 16-bit

    01-Apr-1992 JohnRo
        Prevent too large size requests.
        Use NetApiBufferAllocate() instead of private version.

    05-Dec-1991 RFirth
        Enum returns in TotalEntries (or EntriesLeft) the number of items to
        be enumerated BEFORE this call. Used to be number left after this call

    21-Nov-1991 JohnRo
        Removed NT dependencies to reduce recompiles.

    16-Sep-1991 JohnRo
        Use DBGSTATIC for nonexported routines.

    13-Sep-1991 JohnRo
        Corrected typedef used for descriptors (LPDESC, not LPTSTR).
        Made changes suggested by PC-LINT.

    20-May-1991 RFirth
        Created

--*/



#include "downlevl.h"
#include "rxshare.h"
#include <lmshare.h>    // typedefs for SHARE_INFO etc.



#define SHARE_ADD_LEVEL 2   // only level at which we can add stuff down-stream
#define INITIAL_BUFFER_SIZE 4096    // Arbitrary! But can't be integral multiple of infolen



//
// prototypes
//

DBGSTATIC void
GetShareInfoDescriptors(
    IN  DWORD   level,
    OUT LPDESC* pDesc16,
    OUT LPDESC* pDesc32,
    OUT LPDESC* pDescSmb,
    OUT LPDWORD pDatasize
    );

DBGSTATIC
VOID
ConvertMaxUsesField(
    IN  LPSHARE_INFO_2 Buffer,
    IN  DWORD NumberOfLevel2Structures
    );



NET_API_STATUS
RxNetShareAdd(
    IN  LPTSTR  ServerName,
    IN  DWORD   Level,
    IN  LPBYTE  Buffer,
    OUT LPDWORD ParmError OPTIONAL
    )

/*++

Routine Description:

    Attempts the NetShareAdd API at the named server. The server supports an
    earlier version of LanMan than that under which we are operating so we
    have to slightly modify things in order that the down-level server
    understands the request

    Note: we don't hand back any ParmError information. This level of info
    is primarily supplied by the new (NT) rouines

Arguments:

    ServerName  - at which server to perform this request
    Level       - of information being supplied. Must Be 2
    Buffer      - pointer to supplied level 2 share information buffer
    ParmError   - place to return the id of the parameter causing strife

Return Value:

    NET_API_STATUS:
        Success = NERR_Success
        Failure = ERROR_INVALID_LEVEL
                    Level must be 2
                  (return code from RxRemoteApi)
                  (return code from remoted NetShareAdd API)
--*/

{
    //
    // BUGBUG - check this out???
    //

    UNREFERENCED_PARAMETER(ParmError);
    UNREFERENCED_PARAMETER(Level);


    if ( Buffer == NULL )
        return ERROR_INVALID_PARAMETER;

#if DBG
    //
    // The ServerName parameter must be a non-NUL(L) string. We know this must
    // be so since (presumably) the server name was used as the criteria to get
    // here. Ensure that this is so (in the non-release version) so we trap
    // stupid mistakes early
    //

    NetpAssert(ServerName != NULL);
    NetpAssert(*ServerName);
#endif

    return RxRemoteApi(API_WShareAdd,       // API #
                    ServerName,             // where it will run
                    REMSmb_NetShareAdd_P,   // parameter descriptor
                    REM16_share_info_2,     // Data descriptor/16-bit
                    REM32_share_info_2,     // Data descriptor/32-bit
                    REMSmb_share_info_2,    // Data descriptor/SMB
                    NULL,                   // Aux descriptor/16-bit
                    NULL,                   // Aux descriptor/32-bit
                    NULL,                   // Aux descriptor/SMB
                    FALSE,                  // this call needs user to be logged on
                    SHARE_ADD_LEVEL,        // level. Since there's only 1 push immediate
                    Buffer,                 // caller's SHARE_INFO_2 struct

                    //
                    // we have to supply the size of the buffer - down-level
                    // expects it, NT doesn't. Defined as the size of the fixed
                    // structure (ie a SHARE_INFO_2) plus the lengths of all
                    // the variable fields (all strings in this case)
                    //

                    sizeof(SHARE_INFO_2) +  // parameter supplied by us
                    POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_netname) +
                    POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_remark) +
                    POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_path) +
                    POSSIBLE_STRSIZE(((SHARE_INFO_2*)Buffer)->shi2_passwd)
                    );
}



NET_API_STATUS
RxNetShareCheck(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  DeviceName,
    OUT LPDWORD Type
    )

/*++

Routine Description:

    Attempts to perform the NetShareCheck API on a remote down-level server

Arguments:

    ServerName  - where this call will happen
    DeviceName  - the thing we are querying
    Type        - where we store share type in the (unlikely) event of success

Return Value:

    NET_API_STATUS
        Success = NERR_Success
        Failure =

--*/

{
#if DBG
    //
    // The ServerName parameter must be a non-NUL(L) string. We know this must
    // be so since (presumably) the server name was used as the criteria to get
    // here. Ensure that this is so (in the non-release version) so we trap
    // stupid mistakes early
    //

    NetpAssert(ServerName != NULL);
    NetpAssert(*ServerName);
#endif

    //
    // We have to have something in the device name
    // Ensure that the caller provided us with the address of the place he/she
    // wants the type info to be left
    //

    if (!VALID_STRING(DeviceName) || Type == NULL) {
        return ERROR_INVALID_PARAMETER;
    }

    return RxRemoteApi(API_NetShareCheck,
                    ServerName,             // where it will run
                    REMSmb_NetShareCheck_P, // parameter descriptor
                    NULL,                   // Data descriptor/16-bit
                    NULL,                   // Data descriptor/32-bit
                    NULL,                   // Data descriptor/SMB
                    NULL,                   // Aux descriptor/16-bit
                    NULL,                   // Aux descriptor/32-bit
                    NULL,                   // Aux descriptor/SMB
                    FALSE,                  // this call needs user to be logged on
                    DeviceName,             // parm 1
                    Type                    // parm 2
                    );
}



NET_API_STATUS
RxNetShareDel(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  NetName,
    IN  DWORD   Reserved
    )

/*++

Routine Description:

    Performs the NetShareDel API at a remote down-level server

Arguments:

    ServerName  - where to perform the request
    NetName     - to remove
    Reserved    - MBZ

Return Value:

    NET_API_STATUS
        Success = NERR_Success
        Failure = ERROR_INVALID_PARAMETER

--*/

{
#if DBG
    //
    // The ServerName parameter must be a non-NUL(L) string. We know this must
    // be so since (presumably) the server name was used as the criteria to get
    // here. Ensure that this is so (in the non-release version) so we trap
    // stupid mistakes early
    //

    NetpAssert(ServerName != NULL);
    NetpAssert(*ServerName);
#endif

    //
    // if the NetName parameter is a NULL pointer or string OR the Reserved
    // parameter is NOT 0 then return an error
    //

    if (!VALID_STRING(NetName) || Reserved) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Just call the RpcXlate routine to perform it and return the result
    //

    return RxRemoteApi(API_WShareDel,
                        ServerName,             // where it will run
                        REMSmb_NetShareDel_P,   // parameter descriptor
                        NULL,                   // Data descriptor/16-bit
                        NULL,                   // Data descriptor/32-bit
                        NULL,                   // Data descriptor/SMB
                        NULL,                   // Aux descriptor/16-bit
                        NULL,                   // Aux descriptor/32-bit
                        NULL,                   // Aux descriptor/SMB
                        FALSE,                  // this call needs user to be logged on
                        NetName,                // parm 1
                        0                       // parm 2 (RESERVED - MBZ)
                        );
}



NET_API_STATUS
RxNetShareEnum(
    IN  LPTSTR  ServerName,
    IN  DWORD   Level,
    OUT LPBYTE* Buffer,
    IN  DWORD   PrefMaxLen,
    OUT LPDWORD EntriesRead,
    OUT LPDWORD EntriesLeft,
    IN OUT LPDWORD ResumeHandle OPTIONAL
    )

/*++

Routine Description:

    Performs NetShareEnum API at a remote down-level server. Any returned info
    will be in 32-bit LanMan format. Information returned in buffer sourced by
    this routine. Caller must use NetApiBufferFree when returned buffer no
    longer required

Arguments:

    ServerName  - where to perform the request
    Level       - of info to return. Can be 0, 1 or 2
    Buffer      - pointer to pointer to returned info buffer
    PrefMaxLen  - caller preferred maximum size of returned buffer
    EntriesRead - pointer to number of entries being returned from this call
    EntriesLeft - pointer to total number of share info structures which could be returned
    ResumeHandle- NOT Allowed on down level versions. Must Be NULL

Return Value:

    NET_API_STATUS
        Success = NERR_Success
        Failure = ERROR_INVALID_LEVEL
                    Level parameter not in range 0 <= Level <= 2
                  ERROR_INVALID_PARAMETER
                    Non-NULL ResumeHandle. ResumeHandle can be NULL or a
                    pointer to 0
                  (return code from NetApiBufferAllocate)
                  (return code from RxRemoteApi)
--*/

{
    NET_API_STATUS  rc;
    DWORD   array_size;
    LPDESC  pDesc16;
    LPDESC  pDesc32;
    LPDESC  pDescSmb;
    LPBYTE  ourbuf;
    DWORD   infolen;
    DWORD   entries_read, total_avail;


    UNREFERENCED_PARAMETER(PrefMaxLen);

#if DBG
    //
    // The ServerName parameter must be a non-NUL(L) string. We know this must
    // be so since (presumably) the server name was used as the criteria to get
    // here. Ensure that this is so (in the non-release version) so we trap
    // stupid mistakes early
    //

    NetpAssert(ServerName != NULL);
    NetpAssert(*ServerName);
#endif

    //
    // Set the number of entries read and total available to sensible defaults.
    // Side effect of testing writability of supplied parameters
    //

    //
    // I assume that:
    //  Buffer is a valid, non-NULL pointer
    //  EntriesRead is a valid, non-NULL pointer
    //  EntriesLeft is a valid, non-NULL pointer
    // since these should have been verified at the API level
    //

    *Buffer = NULL;
    *EntriesRead = 0;
    *EntriesLeft = 0;

    //
    // Check for invalid parameters.
    // NB Does Assume that DWORD is unsigned
    // Ensure that:
    //  Level is not >2
    //  ResumeHandle is NULL or a pointer to NULL
    //

    if ((ResumeHandle != NULL) && *ResumeHandle) {
        return ERROR_INVALID_PARAMETER;
    }

    if (Level > 2) {
        return ERROR_INVALID_LEVEL;
    }

    //
    // Decide which descriptors to use, based on the Level parameter
    //

    GetShareInfoDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen);
    ourbuf = NULL;

    //
    // here we used to let RxRemoteApi allocate a buffer (64K intermediate)
    // and do the transaction, returning us a buffer just large enough to
    // hold the returned information. WinBall server barfs if it gets a
    // request with a 64K buffer, so we have to solicit size info until we
    // get everything back. Unfortunately - as of writing - we have no way
    // of knowing the type of server we will make the transaction request to
    // so we may end up having to make >1 request to a LM 2.1 server where
    // we used to be able to get away with 1. On the other hand we can't risk
    // upsetting the WB server. Compromise time. Send a 'reasonable' sized
    // request to the other side (4K buffer). If it isn't sufficient then
    // we loop again, allocating the required buffer
    //

    //
    // what about a LRU cache which keeps the size of the buffer required
    // to satisfy an enum request to a particular down-level server?
    //

    //
    // Loop until we have enough memory or we die for some other reason.
    //

    array_size = INITIAL_BUFFER_SIZE;

    do {

        // Figure out how much memory we need.

        //
        // Remote the API, which will allocate the array for us.
        //

        rc = RxRemoteApi(API_WShareEnum,
                    ServerName,             // where it will run
                    REMSmb_NetShareEnum_P,  // parameter descriptor
                    pDesc16,                // Data descriptor/16-bit
                    pDesc32,                // Data descriptor/32-bit
                    pDescSmb,               // Data descriptor/SMB
                    NULL,                   // Aux descriptor/16-bit
                    NULL,                   // Aux descriptor/32-bit
                    NULL,                   // Aux descriptor/SMB
                    ALLOCATE_RESPONSE,      // allocate a buffer for us
                    Level,                  // level parameter
                    &ourbuf,                // pointer to allocated buffer
                    array_size,             // size of down-level buffer
                    &entries_read,          // pointer to entries read variable
                    &total_avail            // pointer to total entries variable
                    );

        if (rc == ERROR_MORE_DATA) {
            (void) NetApiBufferFree( ourbuf );
            ourbuf = NULL;

            if (array_size >= MAX_TRANSACT_RET_DATA_SIZE) {
                //
                // No point in trying with a larger buffer
                //
                break;
            }
#if DBG
            NetpAssert(array_size != total_avail * infolen);
#endif
            array_size = (total_avail * infolen);
            if (array_size > MAX_TRANSACT_RET_DATA_SIZE) {
                //
                // Try once more with the maximum-size buffer
                //
                array_size = MAX_TRANSACT_RET_DATA_SIZE;
            }
#if DBG
            NetpAssert( array_size != 0 );
#endif
        }
    } while (rc == ERROR_MORE_DATA);

    //
    // if we met with an error then free the allocated buffer and return the
    // error to the caller. If there was no error then we return the items
    // received from the down-level server
    //

    if (rc) {
        if (ourbuf != NULL) {
            (void) NetApiBufferFree(ourbuf);
        }
    } else {
        if (Level == 2) {
            ConvertMaxUsesField((LPSHARE_INFO_2)ourbuf, entries_read);
        }
        *Buffer = ourbuf;
        *EntriesRead = entries_read;
        *EntriesLeft = total_avail;
    }
    return rc;
}



NET_API_STATUS
RxNetShareGetInfo(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  NetName,
    IN  DWORD   Level,
    OUT LPBYTE* Buffer
    )

/*++

Routine Description:

    Performs the NetShareGetInfo API at a remote down-level server. The returned
    information will be in 32-bit LanMan format. Returns single information
    structure in a buffer sourced in this routine. Caller must use
    NetApiBufferFree when finished with buffer

Arguments:

    ServerName  - where to perform the request
    NetName     - name of thing to get information about
    Level       - level of information requested - 0, 1, 2 are valid
    Buffer      - pointer to pointer to returned buffer

Return Value:

    NET_API_STATUS
        Success = NERR_Success
        Failure = ERROR_INVALID_LEVEL
                  ERROR_INVALID_PARAMETER
                  (return code from NetApiBufferAllocate)
                  (return code from RxRemoteApi)
--*/

{
    NET_API_STATUS  rc;
    LPDESC  pDesc16;        // pointer to 16-bit info descriptor for RxRemoteApi
    LPDESC  pDesc32;        // pointer to 32-bit info descriptor for RxRemoteApi
    LPDESC  pDescSmb;       // pointer to SMB info descriptor for RxRemoteApi
    LPBYTE  ourbuf;         // buffer we allocate, fill, and give to the caller
    DWORD   total_avail;    // 32-bit total available if supplied buffer too small
    DWORD   infolen;        // 32-bit place to store size of required buffer


#if DBG
    //
    // The ServerName parameter must be a non-NUL(L) string. We know this must
    // be so since (presumably) the server name was used as the criteria to get
    // here. Ensure that this is so (in the non-release version) so we trap
    // stupid mistakes early
    //

    NetpAssert(ServerName != NULL);
    NetpAssert(*ServerName);
#endif

    //
    // Preset Buffer and check it is valid pointer
    //

    *Buffer = NULL;

    //
    // Perform parameter validity checks:
    //      Level must be in range 0 <= Level <= 2
    //      NetName must be non-NULL pointer to non-NULL string
    //      Buffer must be non-NULL pointer
    // NB. Assumes DWORD is unsigned quantity
    //

    if (Level > 2) {
        return ERROR_INVALID_LEVEL;
    }

    if (!VALID_STRING(NetName) || !Buffer) {
        return ERROR_INVALID_PARAMETER;
    }

    //
    // Work out the descriptor and buffer size requirements based on the
    // requested level
    //

    GetShareInfoDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen);

    //
    // allocate a buffer size required to fit in 1 structure at info level
    // requested. If the allocation fails then return the error
    // We have to allocate space for the strings too, don't forget
    //

    ourbuf = NULL;

    rc = RxRemoteApi(API_WShareGetInfo,
                    ServerName,                 // where it will happen
                    REMSmb_NetShareGetInfo_P,   // parameter descriptor
                    pDesc16,                    // Data descriptor/16-bit
                    pDesc32,                    // Data descriptor/32-bit
                    pDescSmb,                   // Data descriptor/SMB
                    NULL,                       // Aux descriptor/16-bit
                    NULL,                       // Aux descriptor/32-bit
                    NULL,                       // Aux descriptor/SMB
                    ALLOCATE_RESPONSE,          // allocate a buffer for us
                    NetName,                    // pointer to thing to get info on
                    Level,                      // level of info
                    &ourbuf,                    // pointer to buffer sourced by us
                    infolen,                    // size of our sourced buffer
                    &total_avail                // pointer to total available
                    );

    //
    // If the remote NetShareGetInfo call succeeded then give the returned
    // buffer to the caller
    //

    if (rc == NERR_Success) {
        if (Level == 2) {
            ConvertMaxUsesField((LPSHARE_INFO_2)ourbuf, 1);
        }
        *Buffer = ourbuf;
    } else if (ourbuf) {

        //
        // if we didn't record a success then free the buffer we previously allocated
        //

        (void) NetApiBufferFree(ourbuf);
    }
    return rc;
}



NET_API_STATUS
RxNetShareSetInfo(
    IN  LPTSTR  ServerName,
    IN  LPTSTR  NetName,
    IN  DWORD   Level,
    IN  LPBYTE  Buffer,
    OUT LPDWORD ParmError OPTIONAL
    )

/*++

Routine Description:

    Performs the NetShareSetInfo API at a remote down-level server

Arguments:

    ServerName  - where to perform the request
    NetName     - name of thing for which to set info
    Level       - level of information - 0, 1, 2, 1004, 1005, 1006, 1009
    Buffer      - buffer containing info at defined level
    ParmError   - pointer to invalid parameter ordinal

Return Value:

    NET_API_STATUS
        Success = NERR_Success
        Failure = ERROR_INVALID_LEVEL
                  ERROR_INVALID_PARAMETER
                  (return code from RxRemoteApi)
--*/

{
    DWORD   infolen;    // size of structure
    DWORD   parmnum;    // we have to cobble down-level parmnum from Level
    LPDESC  pDesc16;    // used in call to GetShareInfoDescriptors
    LPDESC  pDesc32;    // ditto. Only interested in length of info structure
    LPDESC  pDescSmb;   // ditto. Only interested in length of info structure


    UNREFERENCED_PARAMETER(ParmError);

#if DBG
    //
    // The ServerName parameter must be a non-NUL(L) string. We know this must
    // be so since (presumably) the server name was used as the criteria to get
    // here. Ensure that this is so (in the non-release version) so we trap
    // stupid mistakes early
    //

    NetpAssert(ServerName != NULL);
    NetpAssert(*ServerName);
#endif

    //
    // Perform parameter validity checks:
    //      NetName must be non-NULL pointer to non-NULL string
    //      Buffer must be non-NULL pointer to non-NULL pointer
    //      Level must be in range
    // NB. Assumes that DWORD is unsigned!
    //

    if (!VALID_STRING(NetName) || !Buffer) {
        return ERROR_INVALID_PARAMETER;
    }

    // BUGBUG - are there any manifests for these numbers?

    if (Level < 1 || (Level > 2 && (Level < 1004 || (Level > 1006 && Level != 1009)))) {
        return ERROR_INVALID_LEVEL;
    }

    //
    // We can set individual info fields using the levels > 1000. We have to
    // create level and parmnum info for down-level
    //

    if (Level > 2) {
        //
        // Individual fields are indicated by the old (down-level) parmnum,
        // augmented by 1000. Split level and parmnum parameters
        //

        parmnum = Level - PARMNUM_BASE_INFOLEVEL;
        Level = 2;
        pDesc16 = REM16_share_info_2_setinfo;
        pDesc32 = REM32_share_info_2_setinfo;
        pDescSmb = REMSmb_share_info_2_setinfo;

        switch (parmnum) {
            case 4: // remark
            case 9: // password
                infolen = STRSIZE( (LPTSTR)Buffer );
                break;

            case 5: // permissions
            case 6: // max uses
                infolen = sizeof(WORD);
                break;
        }
    } else {
        //
        // let GetShareInfoDescriptors give us the size of the buffer
        // that NetShareSetInfo thinks its getting. We have no other way of
        // determining this (have we?). Levels 0 - 2 set the entire structure
        //

        GetShareInfoDescriptors(Level, &pDesc16, &pDesc32, &pDescSmb, &infolen);
        parmnum = PARMNUM_ALL;
    }

    return RxRemoteApi(API_WShareSetInfo,
                    ServerName,                 // where it will run
                    REMSmb_NetShareSetInfo_P,   // parameter descriptor
                    pDesc16,                    // Data descriptor/16-bit
                    pDesc32,                    // Data descriptor/32-bit
                    pDescSmb,                   // Data descriptor/SMB
                    NULL,                       // Aux descriptor/16-bit
                    NULL,                       // Aux descriptor/32-bit
                    NULL,                       // Aux descriptor/SMB
                    FALSE,                      // this call needs user to be logged on
                    NetName,                    // pointer to thing to set info on
                    Level,                      // level of info
                    Buffer,                     // pointer to buffer sourced by caller
                    infolen,                    // size of our buffer

                    //
                    // in this case, the field index and parm num are the
                    // same value
                    //

                    MAKE_PARMNUM_PAIR(parmnum, parmnum) // what we're setting
                    );
}



DBGSTATIC void
GetShareInfoDescriptors(
    DWORD   level,
    LPDESC* pDesc16,
    LPDESC* pDesc32,
    LPDESC* pDescSmb,
    LPDWORD pDataSize
    )

/*++

Routine Description:

    A routinette to return pointers to the 16- and 32-bit share info
    structure descriptor strings for each level (0, 1, 2). Also returns
    the size required for a returned 16-bit structure converted to 32-bit data

Arguments:

    level       - of information to be returned
    pDesc16     - pointer to returned 16-bit descriptor string
    pDesc32     - pointer to returned 32-bit descriptor string
    pDescSmb    - pointer to returned SMB descriptor string
    pDataSize   - pointer to returned size of 16-bit structure

Return Value:

    None.

--*/

{
    switch (level) {
        case 0:
            *pDesc16 = REM16_share_info_0;
            *pDesc32 = REM32_share_info_0;
            *pDescSmb = REMSmb_share_info_0;
            *pDataSize = DWORD_ROUNDUP(sizeof(SHARE_INFO_0) // structure size
                            + LM20_NNLEN + 1);              // + shi0_netname len
            break;

        case 1:
            *pDesc16 = REM16_share_info_1;
            *pDesc32 = REM32_share_info_1;
            *pDescSmb = REMSmb_share_info_1;
            *pDataSize = DWORD_ROUNDUP(sizeof(SHARE_INFO_1) // structure size
                            + LM20_NNLEN + 1                // + shi1_netname len
                            + LM20_MAXCOMMENTSZ + 1);       // + shi1_remark len
            break;

        case 2:
            *pDesc16 = REM16_share_info_2;
            *pDesc32 = REM32_share_info_2;
            *pDescSmb = REMSmb_share_info_2;
            *pDataSize = DWORD_ROUNDUP(sizeof(SHARE_INFO_2) // structure size
                            + LM20_NNLEN + 1                // + shi2_netname len
                            + LM20_MAXCOMMENTSZ + 1         // + shi2_remark len
                            + LM20_PATHLEN + 1              // + shi2_path len
                            + SHPWLEN + 1);                 // + shi2_passwd len
            break;

#if DBG
        //
        // just to be completely paranoid...
        //

        default:
            NetpKdPrint(("%s.%u Unknown Level parameter: %u\n", __FILE__, __LINE__, level));
#endif
    }

#if DBG
    NetpAssert(INITIAL_BUFFER_SIZE % *pDataSize);
#endif
}

DBGSTATIC
VOID
ConvertMaxUsesField(
    IN  LPSHARE_INFO_2 Buffer,
    IN  DWORD NumberOfLevel2Structures
    )

/*++

Routine Description:

    Given a buffer containing 1 or more SHARE_INFO_2 structures, converts the
    shi2_max_uses field to a sensible value. The underlying RAP code converts
    the 16-bit number as a signed value, such that 32768 => -32768L. 65535 is
    the only 16-bit value which should be sign-extended. Everything else
    should be represented as the same number in 32-bits

Arguments:

    Buffer                      - pointer to list of SHARE_INFO_2 structures
    NumberOfLevel2Structures    - how many structures in list

Return Value:

    None.

--*/

{
    while (NumberOfLevel2Structures--) {
        if (Buffer->shi2_max_uses != -1L) {
            Buffer->shi2_max_uses &= 0xffffL;
        }
        ++Buffer;
    }
}
