static VOID PvfsNotifyProcessEvent( PVOID pContext ) { NTSTATUS ntError = STATUS_SUCCESS; PPVFS_NOTIFY_REPORT_RECORD pReport = (PPVFS_NOTIFY_REPORT_RECORD)pContext; PPVFS_FCB pParentFcb = NULL; PPVFS_FCB pCursor = NULL; PPVFS_FCB pReportParentFcb = NULL; BAIL_ON_INVALID_PTR(pReport, ntError); /* Simply walk up the ancestory and process the notify filter record on top if there is a match */ pCursor = PvfsReferenceFCB(pReport->pFcb); pReportParentFcb = PvfsGetParentFCB(pReport->pFcb); while ((pParentFcb = PvfsGetParentFCB(pCursor)) != NULL) { PvfsReleaseFCB(&pCursor); /* Process buffers before Irp so we don't doubly report a change on a pending Irp that has requested buffering a change log (which shouldn't start until the existing Irp has been completed). */ PvfsNotifyFullReportBuffer(pParentFcb, pReportParentFcb, pReport); PvfsNotifyFullReportIrp(pParentFcb, pReportParentFcb, pReport); pCursor = pParentFcb; } error: if (pCursor) { PvfsReleaseFCB(&pCursor); } if (pReportParentFcb) { PvfsReleaseFCB(&pReportParentFcb); } if (pReport) { PvfsNotifyFullReportCtxFree(&pReport); } return; }
NTSTATUS PvfsCreateFileCheckPendingDelete( PPVFS_FCB pFcb ) { NTSTATUS ntError = STATUS_SUCCESS; PPVFS_FCB pParentFcb = NULL; if (PvfsFcbIsPendingDelete(pFcb)) { ntError = STATUS_DELETE_PENDING; BAIL_ON_NT_STATUS(ntError); } pParentFcb = PvfsGetParentFCB(pFcb); if (pParentFcb && PvfsFcbIsPendingDelete(pParentFcb)) { ntError = STATUS_DELETE_PENDING; BAIL_ON_NT_STATUS(ntError); } ntError = STATUS_SUCCESS; cleanup: if (pParentFcb) { PvfsReleaseFCB(&pParentFcb); } return ntError; error: goto cleanup; }
static VOID PvfsFreeFCB( PPVFS_FCB pFcb ) { if (pFcb) { LWIO_ASSERT(pFcb->BaseControlBlock.pBucket == NULL); LWIO_ASSERT(pFcb->BaseControlBlock.RefCount == 0); if (pFcb->pParentFcb) { PvfsReleaseFCB(&pFcb->pParentFcb); } RtlCStringFree(&pFcb->pszFilename); pthread_rwlock_destroy(&pFcb->rwScbLock); PvfsListDestroy(&pFcb->pScbList); PvfsListDestroy(&pFcb->pNotifyListIrp); PvfsListDestroy(&pFcb->pNotifyListBuffer); PvfsDestroyCB(&pFcb->BaseControlBlock); PVFS_FREE(&pFcb); InterlockedDecrement(&gPvfsDriverState.Counters.Fcb); } return; }
VOID PvfsFreeCreateContext( IN OUT PVOID *ppContext ) { PPVFS_PENDING_CREATE pCreateCtx = NULL; if (ppContext && *ppContext) { pCreateCtx = (PPVFS_PENDING_CREATE)*ppContext; if (pCreateCtx->pIrpContext) { PvfsReleaseIrpContext(&pCreateCtx->pIrpContext); } if (pCreateCtx->pCcb) { PvfsReleaseCCB(pCreateCtx->pCcb); } if (pCreateCtx->pFcb) { PvfsReleaseFCB(&pCreateCtx->pFcb); } RtlCStringFree(&pCreateCtx->pszDiskFilename); RtlCStringFree(&pCreateCtx->pszOriginalFilename); PVFS_FREE(ppContext); } return; }
static VOID PvfsFreeIrpContext( PPVFS_IRP_CONTEXT *ppIrpContext ) { PPVFS_IRP_CONTEXT pIrpCtx = NULL; if (ppIrpContext && *ppIrpContext) { pIrpCtx = *ppIrpContext; if (pIrpCtx->pIrp && PvfsIrpContextCheckFlag(pIrpCtx, PVFS_IRP_CTX_FLAG_PENDED)) { pIrpCtx->pIrp->IoStatusBlock.Status = STATUS_FILE_CLOSED; PvfsAsyncIrpComplete(pIrpCtx); } if (pIrpCtx->pFcb) { PvfsReleaseFCB(&pIrpCtx->pFcb); } pthread_mutex_destroy(&pIrpCtx->Mutex); PVFS_FREE(ppIrpContext); InterlockedDecrement(&gPvfsIrpContextCount); } }
static NTSTATUS PvfsFindParentFCB( PPVFS_FCB *ppParentFcb, PCSTR pszFilename ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_FCB pFcb = NULL; PSTR pszDirname = NULL; PPVFS_CB_TABLE_ENTRY pBucket = NULL; if (LwRtlCStringIsEqual(pszFilename, "/", TRUE)) { ntError = STATUS_SUCCESS; *ppParentFcb = NULL; goto cleanup; } ntError = PvfsFileDirname(&pszDirname, pszFilename); BAIL_ON_NT_STATUS(ntError); ntError = PvfsCbTableGetBucket(&pBucket, &gPvfsDriverState.FcbTable, pszDirname); BAIL_ON_NT_STATUS(ntError); ntError = PvfsCbTableLookup((PPVFS_CONTROL_BLOCK*)OUT_PPVOID(&pFcb), pBucket, pszDirname); if (ntError == STATUS_OBJECT_NAME_NOT_FOUND) { ntError = PvfsCreateFCB( &pFcb, pszDirname, FALSE, 0, 0); } BAIL_ON_NT_STATUS(ntError); *ppParentFcb = PvfsReferenceFCB(pFcb); cleanup: if (pFcb) { PvfsReleaseFCB(&pFcb); } if (pszDirname) { LwRtlCStringFree(&pszDirname); } return ntError; error: goto cleanup; }
static VOID PvfsNotifyFullReportCtxFree( PPVFS_NOTIFY_REPORT_RECORD *ppReport ) { PPVFS_NOTIFY_REPORT_RECORD pReport = NULL; if (ppReport && *ppReport) { pReport = (PPVFS_NOTIFY_REPORT_RECORD)*ppReport; if (pReport->pFcb) { PvfsReleaseFCB(&pReport->pFcb); } LwRtlCStringFree(&pReport->pszFilename); PVFS_FREE(ppReport); } return; }
NTSTATUS PvfsCcbSetFileBasicInformation( PPVFS_CCB pCcb, PFILE_BASIC_INFORMATION pFileInfo ) { NTSTATUS ntError = STATUS_SUCCESS; LONG64 WriteTime = 0; LONG64 AccessTime = 0; FILE_NOTIFY_CHANGE NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS; PVFS_STAT Stat = {0}; BOOLEAN fcbControlLocked = FALSE; PPVFS_FCB pFcb = PvfsReferenceFCB(pCcb->pScb->pOwnerFcb); if (PvfsIsDefaultStream(pCcb->pScb)) { ntError = PvfsValidatePathSCB(pCcb->pScb, &pCcb->FileId); } else { // Have to grab the base file object LWIO_LOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex); ntError = PvfsValidatePathFCB(pFcb, &pFcb->FileId); BAIL_ON_NT_STATUS(ntError); LWIO_UNLOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex); } /* We cant's set the Change Time so ignore it */ WriteTime = pFileInfo->LastWriteTime; AccessTime = pFileInfo->LastAccessTime; /* Ignore 0xffffffff */ if (WriteTime == (LONG64)-1) { WriteTime = 0; } if (AccessTime == (LONG64)-1) { AccessTime = 0; } /* Save for "sticky" WriteTime sematics */ if (WriteTime != 0) { PvfsSetLastWriteTimeFCB(pFcb, WriteTime); } /* Check if we need to preserve any original timestamps */ if (WriteTime == 0 || AccessTime == 0) { if (PvfsIsDefaultStream(pCcb->pScb)) { ntError = PvfsSysFstat(pCcb->fd, &Stat); } else { // Have to grab the stat() on the base file object ntError = PvfsSysStatByFcb(pFcb, &Stat); } BAIL_ON_NT_STATUS(ntError); if (WriteTime == 0) { NotifyFilter &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; ntError = PvfsUnixToWinTime(&WriteTime, Stat.s_mtime); BAIL_ON_NT_STATUS(ntError); } if (AccessTime == 0) { NotifyFilter &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; ntError = PvfsUnixToWinTime(&AccessTime, Stat.s_atime); BAIL_ON_NT_STATUS(ntError); } } ntError = PvfsSysUtimeByFcb(pFcb, WriteTime, AccessTime); BAIL_ON_NT_STATUS(ntError); if (pFileInfo->FileAttributes != 0) { ntError = PvfsSetFileAttributes(pCcb, pFileInfo->FileAttributes); BAIL_ON_NT_STATUS(ntError); } if (NotifyFilter != 0) { PvfsNotifyScheduleFullReport( pFcb, NotifyFilter, FILE_ACTION_MODIFIED, pFcb->pszFilename); } error: LWIO_UNLOCK_MUTEX(fcbControlLocked, &pFcb->BaseControlBlock.Mutex); if (pFcb) { PvfsReleaseFCB(&pFcb); } return ntError; }
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; }