Example #1
0
static
NTSTATUS
SrvUnmarshalRenameInformation(
    PSRV_EXEC_CONTEXT pExecContext
    )
{
    NTSTATUS                   ntStatus     = 0;
    PSRV_PROTOCOL_EXEC_CONTEXT pCtxProtocol = pExecContext->pProtocolContext;
    PSRV_EXEC_CONTEXT_SMB_V1   pCtxSmb1     = pCtxProtocol->pSmb1Context;
    PSRV_TRANS2_STATE_SMB_V1   pTrans2State = NULL;
    ULONG                      ulBytesAvailable  = 0;
    ULONG                      ulOffset          = 0;
    PWSTR                      pwszFilename      = NULL;
    PBYTE                      pDataCursor       = NULL;
    BOOLEAN                    bTreeInLock       = FALSE;
    PSMB_FILE_RENAME_INFO_HEADER pFileRenameInfo = NULL;

    pTrans2State = (PSRV_TRANS2_STATE_SMB_V1)pCtxSmb1->hState;

    pDataCursor = pTrans2State->pData;
    ulOffset    = pTrans2State->pRequestHeader->dataOffset;
    ulBytesAvailable = pTrans2State->pRequestHeader->dataCount;

    if (ulBytesAvailable < sizeof(SMB_FILE_RENAME_INFO_HEADER))
    {
        ntStatus = STATUS_INVALID_NETWORK_RESPONSE;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    pFileRenameInfo   = (PSMB_FILE_RENAME_INFO_HEADER)pDataCursor;
    pDataCursor      += sizeof(SMB_FILE_RENAME_INFO_HEADER);
    ulBytesAvailable -= sizeof(SMB_FILE_RENAME_INFO_HEADER);
    ulOffset         += sizeof(SMB_FILE_RENAME_INFO_HEADER);

    if (ulOffset % 2)
    {
        if (ulBytesAvailable < 1)
        {
            ntStatus = STATUS_INVALID_NETWORK_RESPONSE;
            BAIL_ON_NT_STATUS(ntStatus);
        }

        pDataCursor++;
        ulOffset++;
        ulBytesAvailable--;
    }

    if (!pFileRenameInfo->ulFileNameLength ||
        (ulBytesAvailable < pFileRenameInfo->ulFileNameLength))
    {
        ntStatus = STATUS_INVALID_NETWORK_RESPONSE;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    if (pFileRenameInfo->ulRootDir)
    {
        ntStatus = STATUS_INVALID_PARAMETER;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    pwszFilename = (PWSTR)pDataCursor;

    pTrans2State->usBytesAllocated =
            sizeof(FILE_RENAME_INFORMATION) + pFileRenameInfo->ulFileNameLength;

    ntStatus = SrvAllocateMemory(
                    pTrans2State->usBytesAllocated,
                    (PVOID*)&pTrans2State->pData2);
    BAIL_ON_NT_STATUS(ntStatus);

    ((PFILE_RENAME_INFORMATION)pTrans2State->pData2)->ReplaceIfExists =
                            pFileRenameInfo->ucReplaceIfExists ? TRUE : FALSE;

    ((PFILE_RENAME_INFORMATION)pTrans2State->pData2)->FileNameLength =
                            pFileRenameInfo->ulFileNameLength;

    memcpy((PBYTE)((PFILE_RENAME_INFORMATION)pTrans2State->pData2)->FileName,
           (PBYTE)pwszFilename,
           pFileRenameInfo->ulFileNameLength);

cleanup:

    LWIO_UNLOCK_RWMUTEX(bTreeInLock, &pCtxSmb1->pTree->mutex);

    return ntStatus;

error:

    goto cleanup;
}
Example #2
0
static
NTSTATUS
SrvProtocolEnumCandidateConnections(
    PVOID    pKey,
    PVOID    pData,
    PVOID    pUserData,
    PBOOLEAN pbContinue
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PLWIO_SRV_CONNECTION pConnection = (PLWIO_SRV_CONNECTION)pData;
    PSRV_PROTOCOL_CONNECTION_ENUM_QUERY pConnectionEnumQuery =
                                    (PSRV_PROTOCOL_CONNECTION_ENUM_QUERY)pUserData;
    BOOLEAN bInLock = FALSE;
    PWSTR pwszClientHost = NULL;

    if (pConnectionEnumQuery->pQueryAddress)
    {
        /*
         * Look for connections by computer address first in case
         * that was the qualifier string
         */
        struct addrinfo* pCursor = pConnectionEnumQuery->pQueryAddress;
        BOOLEAN bMatch = FALSE;

        for (; !bMatch && (pCursor != NULL); pCursor = pCursor->ai_next)
        {
            ntStatus = SrvSocketCompareAddress(
                            pConnection->pClientAddress,
                            pConnection->clientAddrLen,
                            pCursor->ai_addr,
                            pCursor->ai_addrlen,
                            &bMatch);
            BAIL_ON_NT_STATUS(ntStatus);
        }

        if (!bMatch)
        {
            pConnection = NULL;
        }
    }

    if (pConnection)
    {
        LWIO_LOCK_RWMUTEX_SHARED(bInLock, &pConnection->mutex);

        ntStatus = SrvSocketAddressToStringW(pConnection->pClientAddress,
                                             &pwszClientHost);
        BAIL_ON_NT_STATUS(ntStatus);

        pConnectionEnumQuery->pwszClientHost    = pwszClientHost;
        pConnectionEnumQuery->pClientAddress    = pConnection->pClientAddress;
        pConnectionEnumQuery->clientAddrLen     = pConnection->clientAddrLen;
        pConnectionEnumQuery->ulConnectionResId
            = pConnection->resource.ulResourceId;

        ntStatus = WireGetCurrentNTTime(&pConnectionEnumQuery->llCurTime);
        BAIL_ON_NT_STATUS(ntStatus);

        switch (SrvConnectionGetProtocolVersion(pConnection))
        {
            case SMB_PROTOCOL_VERSION_1:
                ntStatus = LwRtlRBTreeTraverse(
                                pConnection->pSessionCollection,
                                LWRTL_TREE_TRAVERSAL_TYPE_IN_ORDER,
                                &SrvProtocolProcessCandidateConnection,
                                pConnectionEnumQuery);
                break;

            case SMB_PROTOCOL_VERSION_2:
                ntStatus = LwRtlRBTreeTraverse(
                                pConnection->pSessionCollection,
                                LWRTL_TREE_TRAVERSAL_TYPE_IN_ORDER,
                                &SrvProtocolProcessCandidateConnection2,
                                pConnectionEnumQuery);
                break;

            case SMB_PROTOCOL_VERSION_UNKNOWN:
                /* Ignore connections that are still being established */
                break;

            default:
                ntStatus = STATUS_INTERNAL_ERROR;
                break;
        }
        BAIL_ON_NT_STATUS(ntStatus);
    }

    *pbContinue = TRUE;

cleanup:
    pConnectionEnumQuery->pClientAddress  = NULL;
    pConnectionEnumQuery->clientAddrLen   = 0;
    pConnectionEnumQuery->pwszClientHost  = NULL;

    SRV_SAFE_FREE_MEMORY(pwszClientHost);

    LWIO_UNLOCK_RWMUTEX(bInLock, &pConnection->mutex);

    return ntStatus;

error:
    *pbContinue = FALSE;

    goto cleanup;
}
Example #3
0
static
NTSTATUS
SrvProtocolProcessCandidateTree2(
    PVOID    pKey,
    PVOID    pData,
    PVOID    pUserData,
    PBOOLEAN pbContinue
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PLWIO_SRV_TREE_2 pTree = (PLWIO_SRV_TREE_2)pData;
    PSRV_PROTOCOL_CONNECTION_ENUM_QUERY pConnectionEnumQuery =
                                    (PSRV_PROTOCOL_CONNECTION_ENUM_QUERY)pUserData;
    BOOLEAN bInTreeLock = FALSE;

    if (pConnectionEnumQuery->pwszShareName)
    {
        if (!LwRtlWC16StringIsEqual(pConnectionEnumQuery->pwszShareName,
                                    pTree->pShareInfo->pwszName,
                                    FALSE))
        {
            pTree = NULL;
        }
    }

    if (pTree)
    {
        if (pConnectionEnumQuery->iEntryIndex < pConnectionEnumQuery->iResumeIndex)
        {
            pConnectionEnumQuery->iEntryIndex++;

            pTree = NULL; // Skip
        }
    }

    if (pTree)
    {
        ULONG ulBytesUsed = 0;
        ULONG ulConnId = 0;
        ULONG ulShareType = 0;
        ULONG ulTotalOpenFileCount = 0;
        ULONG ulTotalNumUsers = 0;
        ULONG ulConnectedTime = 0;
        PWSTR pwszUserName = NULL;
        PWSTR pwszNetName = NULL;
        PLWIO_SRV_SESSION_2 pSession = pTree->pSession;

        LWIO_LOCK_RWMUTEX_SHARED(bInTreeLock, &pTree->mutex);

        ulConnId    = pTree->resource.ulResourceId;
        ulShareType = (ULONG)pTree->pShareInfo->Service;

        if (pConnectionEnumQuery->ulInfoLevel == 1)
        {
            ulTotalOpenFileCount = pTree->ulNumOpenFiles;
            /*
             * There's only one user per connection in user-level security
             */
            ulTotalNumUsers      = 1;
            ulConnectedTime      = (pConnectionEnumQuery->llCurTime -
                                    pSession->llBirthTime)
                                   /WIRE_FACTOR_SECS_TO_HUNDREDS_OF_NANOSECS;
            pwszUserName         = pSession->pwszClientPrincipalName;

            if (!pConnectionEnumQuery->pwszShareName)
            {
                pwszNetName = pTree->pShareInfo->pwszName;
            }
            else
            {
                pwszNetName = pConnectionEnumQuery->pwszClientHost;
            }
        }

        switch (pConnectionEnumQuery->ulInfoLevel)
        {
            case 0:
                ntStatus = SrvProtocolProcessConnection_level_0(
                                ulConnId,
                                pConnectionEnumQuery->pBuffer,
                                pConnectionEnumQuery->ulBufferSize,
                                &ulBytesUsed);
                break;

            case 1:
                ntStatus = SrvProtocolProcessSession_level_1(
                                ulConnId,
                                ulShareType,
                                ulTotalOpenFileCount,
                                ulTotalNumUsers,
                                ulConnectedTime,
                                pwszUserName,
                                pwszNetName,
                                pConnectionEnumQuery->pBuffer,
                                pConnectionEnumQuery->ulBufferSize,
                                &ulBytesUsed);
                break;
            default:
                ntStatus = STATUS_INVALID_INFO_CLASS;

                break;
        }
        BAIL_ON_NT_STATUS(ntStatus);

        if (pConnectionEnumQuery->ulEntriesRead > 0 &&
            (pConnectionEnumQuery->ulPreferredMaxLength <
             pConnectionEnumQuery->ulBytesUsed + ulBytesUsed))
        {
            ntStatus = STATUS_END_OF_FILE;
            BAIL_ON_NT_STATUS(ntStatus);
        }

        pConnectionEnumQuery->pBuffer      += ulBytesUsed;
        pConnectionEnumQuery->ulBufferSize -= ulBytesUsed;
        pConnectionEnumQuery->ulBytesUsed  += ulBytesUsed;

        pConnectionEnumQuery->iEntryIndex++;
        pConnectionEnumQuery->ulEntriesRead++;
    }

    *pbContinue = TRUE;

cleanup:
    LWIO_UNLOCK_RWMUTEX(bInTreeLock, &pTree->mutex);

    return ntStatus;

error:
    *pbContinue = FALSE;

    goto cleanup;
}
Example #4
0
NTSTATUS
SrvTree2CreateFile(
    PLWIO_SRV_TREE_2        pTree,
    PWSTR                   pwszFilename,
    PIO_FILE_HANDLE         phFile,
    PIO_FILE_NAME*          ppFilename,
    ACCESS_MASK             desiredAccess,
    LONG64                  allocationSize,
    FILE_ATTRIBUTES         fileAttributes,
    FILE_SHARE_FLAGS        shareAccess,
    FILE_CREATE_DISPOSITION createDisposition,
    FILE_CREATE_OPTIONS     createOptions,
    PLWIO_SRV_FILE_2*       ppFile
    )
{
    NTSTATUS ntStatus = 0;
    BOOLEAN bInLock = FALSE;
    PLWIO_SRV_FILE_2 pFile = NULL;
    SMB2_FID  fid = {0};

    LWIO_LOCK_RWMUTEX_EXCLUSIVE(bInLock, &pTree->mutex);

    if (SrvTree2IsRundown_inlock(pTree))
    {
        ntStatus = STATUS_INVALID_HANDLE;
        BAIL_ON_NT_STATUS(ntStatus);
    }

    ntStatus = SrvTree2AcquireFileId_inlock(
                    pTree,
                    &fid);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvFile2Create(
                    pTree,
                    &fid,
                    pwszFilename,
                    phFile,
                    ppFilename,
                    desiredAccess,
                    allocationSize,
                    fileAttributes,
                    shareAccess,
                    createDisposition,
                    createOptions,
                    &pFile);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvTree2AddFile_inlock(pTree, pFile);
    BAIL_ON_NT_STATUS(ntStatus);

    SrvFile2BlockIdleTimeout(pFile);

    *ppFile = pFile;

cleanup:

    LWIO_UNLOCK_RWMUTEX(bInLock, &pTree->mutex);

    return ntStatus;

error:

    LWIO_UNLOCK_RWMUTEX(bInLock, &pTree->mutex);

    *ppFile = NULL;

    if (pFile)
    {
        SrvFile2Rundown(pFile);
        SrvFile2Release(pFile);
    }

    goto cleanup;
}
Example #5
0
NTSTATUS
SrvProtocolEnumerateConnections(
    PWSTR  pwszComputerName,
    PWSTR  pwszShareName,
    ULONG  ulInfoLevel,
    ULONG  ulPreferredMaxLength,
    PBYTE  pBuffer,
    ULONG  ulBufferSize,
    PULONG pulBytesUsed,
    PULONG pulEntriesRead,
    PULONG pulTotalEntries,
    PULONG pulResumeHandle
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    BOOLEAN  bInLock  = FALSE;
    BOOLEAN  bMoreData = FALSE;
    SRV_PROTOCOL_CONNECTION_ENUM_QUERY ConnectionEnumQuery =
    {
            .pwszComputerName     = pwszComputerName,
            .pwszShareName        = pwszShareName,
            .pClientAddress       = NULL,
            .clientAddrLen        = 0,
            .pwszClientHost       = NULL,
            .ulInfoLevel          = ulInfoLevel,
            .ulPreferredMaxLength = ulPreferredMaxLength,
            .iEntryIndex          = 0,
            .iResumeIndex         = pulResumeHandle ? *pulResumeHandle : 0,
            .ulEntriesRead        = 0,
            .ulTotalEntries       = 0,
            .pBuffer              = pBuffer,
            .ulBufferSize         = ulBufferSize,
            .ulBytesUsed          = 0,
            .pQueryAddress        = NULL
    };

    if (pwszComputerName)
    {
        wchar16_t wszPrefix[] = {'\\','\\', 0};
        size_t    sPrefixLen =
                (sizeof(wszPrefix)-sizeof(wszPrefix[0]))/sizeof(wszPrefix[0]);

        if (!SMBWc16snCmp(pwszComputerName, &wszPrefix[0], sPrefixLen))
        {
            pwszComputerName += sPrefixLen;
        }

        ConnectionEnumQuery.pwszComputerName = pwszComputerName;

        ntStatus = SrvSocketGetAddrInfoW(
                        pwszComputerName,
                        &ConnectionEnumQuery.pQueryAddress);
        BAIL_ON_NT_STATUS(ntStatus);
    }

    LWIO_LOCK_RWMUTEX_SHARED(bInLock, &gProtocolApiGlobals.mutex);

    ntStatus = LwRtlRBTreeTraverse(
                    gProtocolApiGlobals.pConnections,
                    LWRTL_TREE_TRAVERSAL_TYPE_IN_ORDER,
                    &SrvProtocolCountCandidateConnections,
                    &ConnectionEnumQuery);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = LwRtlRBTreeTraverse(
                    gProtocolApiGlobals.pConnections,
                    LWRTL_TREE_TRAVERSAL_TYPE_IN_ORDER,
                    &SrvProtocolEnumCandidateConnections,
                    &ConnectionEnumQuery);
    /* If we still have more data to read, then return MORE_ENTRIES */
    if (ntStatus == STATUS_END_OF_FILE &&
        ConnectionEnumQuery.ulEntriesRead < ConnectionEnumQuery.ulTotalEntries)
    {
        bMoreData = TRUE;
        ntStatus = STATUS_SUCCESS;
    }
    BAIL_ON_NT_STATUS(ntStatus);

    *pulBytesUsed    = ConnectionEnumQuery.ulBytesUsed;
    *pulEntriesRead  = ConnectionEnumQuery.ulEntriesRead;
    *pulTotalEntries = ConnectionEnumQuery.ulTotalEntries;
    if (pulResumeHandle)
    {
        *pulResumeHandle =
                ConnectionEnumQuery.iResumeIndex + ConnectionEnumQuery.ulEntriesRead;
    }

cleanup:
    LWIO_UNLOCK_RWMUTEX(bInLock, &gProtocolApiGlobals.mutex);

    SrvProtocolFreeConnectionEnumQueryContents(&ConnectionEnumQuery);

    return (NT_SUCCESS(ntStatus) && bMoreData ? STATUS_MORE_ENTRIES : ntStatus);

error:
    *pulBytesUsed    = 0;
    *pulEntriesRead  = 0;
    *pulTotalEntries = 0;

    if (pBuffer && ulBufferSize)
    {
        memset(pBuffer, 0, ulBufferSize);
    }

    goto cleanup;
}


static
NTSTATUS
SrvProtocolCountCandidateConnections(
    PVOID    pKey,
    PVOID    pData,
    PVOID    pUserData,
    PBOOLEAN pbContinue
    )
{
    NTSTATUS ntStatus = STATUS_SUCCESS;
    PLWIO_SRV_CONNECTION pConnection = (PLWIO_SRV_CONNECTION)pData;
    PSRV_PROTOCOL_CONNECTION_ENUM_QUERY pConnectionEnumQuery =
                                    (PSRV_PROTOCOL_CONNECTION_ENUM_QUERY)pUserData;
    ULONG ulTotalConnectionCount = pConnectionEnumQuery->ulTotalEntries;
    ULONG ulConnectionCount = 0;


    if (pConnectionEnumQuery->pQueryAddress)
    {
        /*
         * Look for connections by computer address first in case
         * that was the qualifier string
         */
        struct addrinfo* pCursor = pConnectionEnumQuery->pQueryAddress;
        BOOLEAN bMatch = FALSE;

        for (; !bMatch && (pCursor != NULL); pCursor = pCursor->ai_next)
        {
            ntStatus = SrvSocketCompareAddress(
                            pConnection->pClientAddress,
                            pConnection->clientAddrLen,
                            pCursor->ai_addr,
                            pCursor->ai_addrlen,
                            &bMatch);
            BAIL_ON_NT_STATUS(ntStatus);
        }

        if (!bMatch)
        {
            pConnection = NULL;
        }
    }

    if (pConnection)
    {
        switch (SrvConnectionGetProtocolVersion(pConnection))
        {
            case SMB_PROTOCOL_VERSION_1:
                ntStatus = SrvConnectionGetConnectionCount(
                                pConnection,
                                pConnectionEnumQuery->pwszShareName,
                                &ulConnectionCount);

                break;

            case SMB_PROTOCOL_VERSION_2:
                ntStatus = SrvConnectionGetConnectionCount2(
                                pConnection,
                                pConnectionEnumQuery->pwszShareName,
                                &ulConnectionCount);

                break;

            case SMB_PROTOCOL_VERSION_UNKNOWN:
                /* Ignore connections that are still being established */
                break;

            default:
                ntStatus = STATUS_INTERNAL_ERROR;
                break;
        }
        BAIL_ON_NT_STATUS(ntStatus);

        ulTotalConnectionCount += ulConnectionCount;

        pConnectionEnumQuery->ulTotalEntries = ulTotalConnectionCount;
    }

    *pbContinue = TRUE;

cleanup:
    return ntStatus;

error:
    *pbContinue = FALSE;

    goto cleanup;
}
Example #6
0
NTSTATUS
SrvTreeCreateFile(
    PLWIO_SRV_TREE          pTree,
    PWSTR                   pwszFilename,
    PIO_FILE_HANDLE         phFile,
    PIO_FILE_NAME*          ppFilename,
    ACCESS_MASK             desiredAccess,
    LONG64                  allocationSize,
    FILE_ATTRIBUTES         fileAttributes,
    FILE_SHARE_FLAGS        shareAccess,
    FILE_CREATE_DISPOSITION createDisposition,
    FILE_CREATE_OPTIONS     createOptions,
    PLWIO_SRV_FILE*         ppFile
    )
{
    NTSTATUS ntStatus = 0;
    BOOLEAN bInLock = FALSE;
    PLWIO_SRV_FILE pFile = NULL;
    USHORT  fid = 0;

    LWIO_LOCK_RWMUTEX_EXCLUSIVE(bInLock, &pTree->mutex);

    ntStatus = SrvTreeAcquireFileId_inlock(
                    pTree,
                    &fid);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = SrvFileCreate(
                    fid,
                    pwszFilename,
                    phFile,
                    ppFilename,
                    desiredAccess,
                    allocationSize,
                    fileAttributes,
                    shareAccess,
                    createDisposition,
                    createOptions,
                    &pFile);
    BAIL_ON_NT_STATUS(ntStatus);

    ntStatus = LwRtlRBTreeAdd(
                    pTree->pFileCollection,
                    &pFile->fid,
                    pFile);
    BAIL_ON_NT_STATUS(ntStatus);

    pFile->resource.pAttributes->treeId.usTid    = pTree->tid;
    pFile->resource.pAttributes->sessionId.usUid = pTree->uid;
    pFile->resource.pAttributes->ulConnectionResourceId =
                                                pTree->ulConnectionResourceId;

    pTree->ulNumOpenFiles++;

    *ppFile = SrvFileAcquire(pFile);

cleanup:

    LWIO_UNLOCK_RWMUTEX(bInLock, &pTree->mutex);

    return ntStatus;

error:

    *ppFile = NULL;

    if (pFile)
    {
        SrvFileRelease(pFile);
    }

    goto cleanup;
}
Example #7
0
NTSTATUS
PvfsRemoveStreamObjects(
    IN PPVFS_FCB pFcb
    )
{
    NTSTATUS status = STATUS_SUCCESS;
    BOOLEAN scbBucketLocked = FALSE;
    BOOLEAN scbLocked = FALSE;
    PLW_LIST_LINKS scbCursorLink = NULL;
    PPVFS_SCB scbCursor = NULL;
    PPVFS_FILE_NAME streamName = NULL;
    PSTR fullStreamName = NULL;
    PPVFS_CB_TABLE_ENTRY scbCursorBucket = NULL;

    for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL);
         scbCursorLink;
         scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink))
    {
        scbCursor = LW_STRUCT_FROM_FIELD(
                          scbCursorLink,
                          PVFS_SCB,
                          FcbList);

        LWIO_ASSERT(scbCursor->OpenHandleCount == 0);

        status = PvfsAllocateFileNameFromScb(&streamName, scbCursor);
        BAIL_ON_NT_STATUS(status);

        status = PvfsAllocateCStringFromFileName(&fullStreamName, streamName);
        BAIL_ON_NT_STATUS(status);

        LWIO_LOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex);

        scbCursorBucket = scbCursor->BaseControlBlock.pBucket;
        LWIO_LOCK_RWMUTEX_EXCLUSIVE(scbBucketLocked, &scbCursorBucket->rwLock);

        status = PvfsCbTableRemove_inlock(
                      (PPVFS_CONTROL_BLOCK)scbCursor,
                      fullStreamName);
        LWIO_ASSERT(STATUS_SUCCESS == status);

        LWIO_UNLOCK_RWMUTEX(scbBucketLocked, &scbCursorBucket->rwLock);
        LWIO_UNLOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex);

        if (streamName)
        {
            PvfsFreeFileName(streamName);
            streamName = NULL;
        }
        if (fullStreamName)
        {
            LwRtlCStringFree(&fullStreamName);
        }
    }

error:

    LWIO_UNLOCK_RWMUTEX(scbBucketLocked, &scbCursorBucket->rwLock);
    LWIO_UNLOCK_MUTEX(scbLocked, &scbCursor->BaseControlBlock.Mutex);

    if (streamName)
    {
        PvfsFreeFileName(streamName);
    }
    if (fullStreamName)
    {
        LwRtlCStringFree(&fullStreamName);
    }

    return status;
}
Example #8
0
NTSTATUS
PvfsRenameFCB(
    PPVFS_FCB pFcb,
    PPVFS_CCB pCcb,
    PPVFS_FILE_NAME pNewFilename
    )
{
    NTSTATUS ntError = STATUS_SUCCESS;
    PPVFS_CB_TABLE fcbTable = &gPvfsDriverState.FcbTable;
    PPVFS_FCB pNewParentFcb = NULL;
    PPVFS_FCB pOldParentFcb = NULL;
    PPVFS_FCB pTargetFcb = NULL;
    PPVFS_CB_TABLE_ENTRY pTargetBucket = NULL;
    PPVFS_CB_TABLE_ENTRY pCurrentBucket = NULL;
    BOOLEAN currentFcbControl = FALSE;
    BOOLEAN targetFcbListLocked = FALSE;
    BOOLEAN targetBucketLocked = FALSE;
    BOOLEAN currentBucketLocked = FALSE;
    BOOLEAN fcbRwLocked = FALSE;
    BOOLEAN renameLock = FALSE;
    PPVFS_FILE_NAME currentFileName = NULL;

    /* If the target has an existing SCB, remove it from the Table and let
       the existing ref counters play out (e.g. pending change notifies. */

    BAIL_ON_INVALID_PTR(pNewFilename, ntError);

    ntError = PvfsFindParentFCB(&pNewParentFcb, pNewFilename->FileName);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsAllocateFileNameFromScb(&currentFileName, pCcb->pScb);
    BAIL_ON_NT_STATUS(ntError);

    // Obtain all locks for the rename
    LWIO_LOCK_RWMUTEX_EXCLUSIVE(renameLock, &fcbTable->rwLock);
    LWIO_LOCK_MUTEX(currentFcbControl, &pFcb->BaseControlBlock.Mutex);

    pCurrentBucket = pFcb->BaseControlBlock.pBucket;

    ntError = PvfsCbTableGetBucket(
                  &pTargetBucket,
                  fcbTable,
                  pNewFilename->FileName);
    BAIL_ON_NT_STATUS(ntError);

    LWIO_LOCK_RWMUTEX_EXCLUSIVE(currentBucketLocked, &pCurrentBucket->rwLock);
    if (pCurrentBucket != pTargetBucket)
    {
        LWIO_LOCK_RWMUTEX_EXCLUSIVE(targetBucketLocked, &pTargetBucket->rwLock);
    }

    // Do the rename work now
    ntError = PvfsCbTableLookup_inlock(
                  (PPVFS_CONTROL_BLOCK*)OUT_PPVOID(&pTargetFcb),
                  pTargetBucket,
                  pNewFilename->FileName);
    if (ntError == STATUS_SUCCESS)
    {
        if (pTargetFcb != pFcb)
        {
            // Remove an existing FCB for the target file/stream (if one exists)
            // But make sure it is a different FCB

            LWIO_LOCK_RWMUTEX_SHARED(targetFcbListLocked, &pTargetFcb->rwScbLock);

            if (pTargetFcb->OpenHandleCount > 0 )
            {
                // if TargetScb has open handles cannot rename
                // This except in the batch-oplock case
                ntError = STATUS_INVALID_PARAMETER;
                BAIL_ON_NT_STATUS(ntError);
            }

            LWIO_UNLOCK_RWMUTEX(targetFcbListLocked, &pTargetFcb->rwScbLock);

            // TODO - How to get the Control Mutex without violating the
            // lock heirarchy?  Does it matter at all ?

            ntError = PvfsRemoveStreamObjects(pTargetFcb);
            LWIO_ASSERT(STATUS_SUCCESS == ntError);

            ntError = PvfsCbTableRemove_inlock(
                          (PPVFS_CONTROL_BLOCK)pTargetFcb,
                          pTargetFcb->pszFilename);
            LWIO_ASSERT(STATUS_SUCCESS == ntError);
        }
    }

    ntError = PvfsSysRenameByFileName(currentFileName, pNewFilename);
    // Ignore the error here and continue

    ntError = PvfsPathCacheRemove(currentFileName);
    // Ignore the error here and continue

    /* Remove the SCB from the table, update the lookup key, and then re-add.
       Otherwise you will get memory corruption as a freed pointer gets left
       in the Table because if cannot be located using the current (updated)
       filename. Another reason to use the dev/inode pair instead if we could
       solve the "Create New File" issue. */

    // Remove FCB
    ntError = PvfsCbTableRemove_inlock(
                  (PPVFS_CONTROL_BLOCK)pFcb,
                  pFcb->pszFilename);
    LWIO_ASSERT(STATUS_SUCCESS == ntError);

    // Rename FCB & Update parent links
    LWIO_LOCK_RWMUTEX_EXCLUSIVE(fcbRwLocked, &pFcb->BaseControlBlock.RwLock);
    LwRtlCStringFree(&pFcb->pszFilename);

    ntError = LwRtlCStringDuplicate(&pFcb->pszFilename, pNewFilename->FileName);
    BAIL_ON_NT_STATUS(ntError);

    if (pNewParentFcb != pFcb->pParentFcb)
    {
        pOldParentFcb = pFcb->pParentFcb;
        pFcb->pParentFcb = pNewParentFcb;
        pNewParentFcb = NULL;
    }
    LWIO_UNLOCK_RWMUTEX(fcbRwLocked, &pFcb->BaseControlBlock.RwLock);

    // Re-Add SCB
    ntError = PvfsCbTableAdd_inlock(
                  pTargetBucket,
                  pFcb->pszFilename,
                  (PPVFS_CONTROL_BLOCK)pFcb);
    BAIL_ON_NT_STATUS(ntError);

error:

    // Release all locks .. Whew!
    LWIO_UNLOCK_RWMUTEX(targetFcbListLocked, &pTargetFcb->rwScbLock);
    LWIO_UNLOCK_RWMUTEX(targetBucketLocked, &pTargetBucket->rwLock);
    LWIO_UNLOCK_RWMUTEX(currentBucketLocked, &pCurrentBucket->rwLock);
    LWIO_UNLOCK_RWMUTEX(fcbRwLocked, &pFcb->BaseControlBlock.RwLock);
    LWIO_UNLOCK_MUTEX(currentFcbControl, &pFcb->BaseControlBlock.Mutex);
    LWIO_UNLOCK_RWMUTEX(renameLock, &fcbTable->rwLock);

    if (pNewParentFcb)
    {
        PvfsReleaseFCB(&pNewParentFcb);
    }
    if (pOldParentFcb)
    {
        PvfsReleaseFCB(&pOldParentFcb);
    }
    if (pTargetFcb)
    {
        PvfsReleaseFCB(&pTargetFcb);
    }
    if (currentFileName)
    {
        PvfsFreeFileName(currentFileName);
    }

    return ntError;
}
Example #9
0
NTSTATUS
PvfsCreateFCB(
    OUT PPVFS_FCB *ppFcb,
    IN PCSTR pszFilename,
    IN BOOLEAN bCheckShareAccess,
    IN FILE_SHARE_FLAGS SharedAccess,
    IN ACCESS_MASK DesiredAccess
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    PPVFS_FCB pFcb = NULL;
    BOOLEAN bBucketLocked = FALSE;
    PPVFS_CB_TABLE_ENTRY pBucket = NULL;
    PPVFS_FCB pParentFcb = NULL;

    ntError = PvfsFindParentFCB(&pParentFcb, pszFilename);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCbTableGetBucket(&pBucket, &gPvfsDriverState.FcbTable, (PVOID)pszFilename);
    BAIL_ON_NT_STATUS(ntError);

    /* Protect against adding a duplicate */

    LWIO_LOCK_RWMUTEX_EXCLUSIVE(bBucketLocked, &pBucket->rwLock);

    ntError = PvfsCbTableLookup_inlock(
                  (PPVFS_CONTROL_BLOCK*)OUT_PPVOID(&pFcb),
                  pBucket,
                  pszFilename);
    if (ntError == STATUS_SUCCESS)
    {
        LWIO_UNLOCK_RWMUTEX(bBucketLocked, &pBucket->rwLock);

        /* If we have success, then we are good.  If we have a sharing
           violation, give the caller a chance to break the oplock and
           we'll try again when the create is resumed. */

        if (ntError == STATUS_SUCCESS ||
            ntError == STATUS_SHARING_VIOLATION)
        {
            *ppFcb = PvfsReferenceFCB(pFcb);
        }

        goto cleanup;
    }

    ntError = PvfsAllocateFCB(&pFcb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = RtlCStringDuplicate(&pFcb->pszFilename, pszFilename);
    BAIL_ON_NT_STATUS(ntError);

    pFcb->pParentFcb = pParentFcb ? PvfsReferenceFCB(pParentFcb) : NULL;

    // New FCB so BaseControlBlock.Mutext locking is not necessary

    ntError = PvfsCbTableAdd_inlock(
                  pBucket,
                  pFcb->pszFilename,
                  (PPVFS_CONTROL_BLOCK)pFcb);
    BAIL_ON_NT_STATUS(ntError);

    /* Return a reference to the FCB */

    *ppFcb = PvfsReferenceFCB(pFcb);

cleanup:
    LWIO_UNLOCK_RWMUTEX(bBucketLocked, &pBucket->rwLock);

    if (pParentFcb)
    {
        PvfsReleaseFCB(&pParentFcb);
    }

    if (pFcb)
    {
        PvfsReleaseFCB(&pFcb);
    }

    return ntError;

error:
    goto cleanup;
}
Example #10
0
static
NTSTATUS
PvfsRenameFile(
    PPVFS_CCB pCcb,
    PPVFS_FILE_NAME pNewFileName
    )
{
    NTSTATUS ntError = STATUS_SUCCESS;
    PPVFS_CB_TABLE scbTable = &gPvfsDriverState.ScbTable;
    PPVFS_CB_TABLE_ENTRY pTargetBucket = NULL;
    PPVFS_CB_TABLE_ENTRY pCurrentBucket = NULL;
    BOOLEAN renameLock = FALSE;
    BOOLEAN targetBucketLock = FALSE;
    BOOLEAN currentBucketLock = FALSE;
    PPVFS_FCB pFcb = NULL;
    PLW_LIST_LINKS scbCursorLink = NULL;
    PPVFS_SCB scbCursor = NULL;
    BOOLEAN scbMutexLock = FALSE;
    BOOLEAN fcbListLocked = FALSE;
    PPVFS_FILE_NAME origTargetFileName = NULL;
    PPVFS_FILE_NAME scbCursorFileName = NULL;
    PSTR origFullStreamName = NULL;
    PSTR newFullStreamName = NULL;

    // The CCB holds out reference down the chain so no need to take a new one
    pFcb = pCcb->pScb->pOwnerFcb;

    ntError = PvfsAllocateFileNameFromScb(&origTargetFileName, pCcb->pScb);
    BAIL_ON_NT_STATUS(ntError);

    LWIO_LOCK_RWMUTEX_EXCLUSIVE(renameLock, &scbTable->rwLock);
    LWIO_LOCK_RWMUTEX_SHARED(fcbListLocked, &pFcb->rwScbLock);

    ntError = PvfsRenameFCB(pFcb, pCcb, pNewFileName);
    BAIL_ON_NT_STATUS(ntError);

    for (scbCursorLink = PvfsListTraverse(pFcb->pScbList, NULL);
         scbCursorLink;
         scbCursorLink = PvfsListTraverse(pFcb->pScbList, scbCursorLink))
    {
        scbCursor = LW_STRUCT_FROM_FIELD(
                          scbCursorLink,
                          PVFS_SCB,
                          FcbList);

        ntError = PvfsAllocateFileNameFromScb(&scbCursorFileName, scbCursor);
        BAIL_ON_NT_STATUS(ntError);

        ntError = PvfsAllocateCStringFromFileName(
                      &newFullStreamName,
                      scbCursorFileName);
        BAIL_ON_NT_STATUS(ntError);

        ntError = PvfsRenameBaseFileName(
                      scbCursorFileName,
                      PvfsGetCStringBaseFileName(origTargetFileName));
        BAIL_ON_NT_STATUS(ntError);

        ntError = PvfsAllocateCStringFromFileName(
                      &origFullStreamName,
                      scbCursorFileName);
        BAIL_ON_NT_STATUS(ntError);

        pCurrentBucket = scbCursor->BaseControlBlock.pBucket;

        ntError = PvfsCbTableGetBucket(&pTargetBucket, scbTable, newFullStreamName);
        BAIL_ON_NT_STATUS(ntError);

        LWIO_LOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex);
        LWIO_LOCK_RWMUTEX_EXCLUSIVE(currentBucketLock, &pCurrentBucket->rwLock);
        if (pCurrentBucket != pTargetBucket)
        {
            // Will be moved to a new bucket in the table
            LWIO_LOCK_RWMUTEX_EXCLUSIVE(targetBucketLock, &pTargetBucket->rwLock);
        }

        ntError = PvfsCbTableRemove_inlock(
                      (PPVFS_CONTROL_BLOCK)scbCursor,
                      origFullStreamName);
        LWIO_ASSERT(STATUS_SUCCESS == ntError);

        ntError = PvfsCbTableAdd_inlock(
                      pTargetBucket,
                      newFullStreamName,
                     (PPVFS_CONTROL_BLOCK)scbCursor);
        if (STATUS_SUCCESS != ntError)
        {
            LWIO_LOG_ERROR(
                "Failed to rename stream \"%s\" (%s)\n",
                newFullStreamName,
                LwNtStatusToName(ntError));
        }

        LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock);
        LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock);
        LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex);

        if (origFullStreamName)
        {
            LwRtlCStringFree(&origFullStreamName);
        }
        if (newFullStreamName)
        {
            LwRtlCStringFree(&newFullStreamName);
        }
    }

error:
    LWIO_UNLOCK_MUTEX(scbMutexLock, &scbCursor->BaseControlBlock.Mutex);
    LWIO_UNLOCK_RWMUTEX(targetBucketLock, &pTargetBucket->rwLock);
    LWIO_UNLOCK_RWMUTEX(currentBucketLock, &pCurrentBucket->rwLock);

    LWIO_UNLOCK_RWMUTEX(fcbListLocked, &pFcb->rwScbLock);
    LWIO_UNLOCK_RWMUTEX(renameLock, &scbTable->rwLock);

    if (origTargetFileName)
    {
        PvfsFreeFileName(origTargetFileName);
    }
    if (origFullStreamName)
    {
        LwRtlCStringFree(&origFullStreamName);
    }
    if (newFullStreamName)
    {
        LwRtlCStringFree(&newFullStreamName);
    }

    return ntError;
}