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; }
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; }
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; }
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; }
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; }
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; }
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; }
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(¤tFileName, 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; }
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; }
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; }