NTSTATUS NpfsCreateFCB( PUNICODE_STRING pUnicodeString, PNPFS_FCB * ppFCB ) { NTSTATUS ntStatus = 0; PNPFS_FCB pFCB = NULL; ntStatus = NpfsAllocateMemory( sizeof(*pFCB), OUT_PPVOID(&pFCB) ); BAIL_ON_NT_STATUS(ntStatus); LwListInit(&pFCB->link); LwListInit(&pFCB->pipeList); ntStatus = RtlUnicodeStringDuplicate( &pFCB->PipeName, pUnicodeString ); BAIL_ON_NT_STATUS(ntStatus); pthread_rwlock_init(&pFCB->PipeListRWLock, NULL); pFCB->lRefCount = 1; pFCB->MaxNumberOfInstances = 0xFF; // Number of currently available instances pFCB->CurrentNumberOfInstances = 0xFF; // TODO: This should be the default type pFCB->NamedPipeType = FILE_PIPE_MESSAGE_TYPE; LwListInsertBefore(&gFCBList, &pFCB->link); *ppFCB = pFCB; return ntStatus; error: if (pFCB) { NpfsFreeMemory(pFCB); } *ppFCB = NULL; return ntStatus; }
static NTSTATUS IopDeviceAllocate( OUT PIO_DEVICE_OBJECT* ppDeviceObject, IN PIO_DRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pDeviceName, IN OPTIONAL PVOID DeviceContext ) { NTSTATUS status = 0; int EE = 0; PIO_DEVICE_OBJECT pDeviceObject = NULL; status = IO_ALLOCATE(&pDeviceObject, IO_DEVICE_OBJECT, sizeof(*pDeviceObject)); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pDeviceObject->ReferenceCount = 1; pDeviceObject->Driver = pDriverObject; IopDriverReference(pDriverObject); pDeviceObject->Context = DeviceContext; LwListInit(&pDeviceObject->FileObjectsList); // Initialize links too LwListInit(&pDeviceObject->DriverLinks); LwListInit(&pDeviceObject->RootLinks); LwListInit(&pDeviceObject->RundownLinks); status = LwRtlUnicodeStringDuplicate(&pDeviceObject->DeviceName, pDeviceName); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = LwRtlInitializeMutex(&pDeviceObject->Mutex, TRUE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = LwRtlInitializeMutex(&pDeviceObject->CancelMutex, TRUE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); cleanup: if (status) { IopDeviceDereference(&pDeviceObject); } *ppDeviceObject = pDeviceObject; IO_LOG_ENTER_LEAVE_STATUS_EE(status, EE); return status; }
NTSTATUS NpfsAllocateIrpContext( PIRP pIrp, PNPFS_IRP_CONTEXT * ppIrpContext ) { NTSTATUS ntStatus = 0; PNPFS_IRP_CONTEXT pIrpContext = NULL; ntStatus = IO_ALLOCATE(&pIrpContext, NPFS_IRP_CONTEXT, sizeof(*pIrpContext)); BAIL_ON_NT_STATUS(ntStatus); LwListInit(&pIrpContext->Link); pIrpContext->pIrp = pIrp; *ppIrpContext = pIrpContext; return(ntStatus); error: *ppIrpContext = NULL; return(ntStatus); }
NTSTATUS RdrCreateContextArray( PIRP pIrp, ULONG ulCount, PRDR_OP_CONTEXT* ppContexts ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContexts = NULL; ULONG ulIndex = 0; status = LW_RTL_ALLOCATE_ARRAY_AUTO(&pContexts, ulCount); BAIL_ON_NT_STATUS(status); for (ulIndex = 0; ulIndex < ulCount; ulIndex++) { LwListInit(&pContexts[ulIndex].Link); pContexts[ulIndex].pIrp = pIrp; } *ppContexts = pContexts; error: return status; }
NTSTATUS RdrCreateContext( PIRP pIrp, PRDR_OP_CONTEXT* ppContext ) { NTSTATUS status = STATUS_SUCCESS; PRDR_OP_CONTEXT pContext = NULL; status = LW_RTL_ALLOCATE_AUTO(&pContext); BAIL_ON_NT_STATUS(status); LwListInit(&pContext->Link); pContext->pIrp = pIrp; if (pIrp) { LWIO_LOG_DEBUG("Created op context %p for IRP %p", pContext, pIrp); } else { LWIO_LOG_DEBUG("Created op context %p", pContext); } *ppContext = pContext; error: return status; }
NTSTATUS PvfsListInit( PPVFS_LIST *ppNewList, DWORD dwMaxSize, PPVFS_LIST_FREE_DATA_FN pfnFreeData ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PPVFS_LIST pList = NULL; BAIL_ON_INVALID_PTR(ppNewList, ntError); ntError = RTL_ALLOCATE(&pList, PVFS_LIST, sizeof(PVFS_LIST)); BAIL_ON_NT_STATUS(ntError); pList->MaxSize = dwMaxSize; pList->CurrentSize = 0; pList->pfnFreeData = pfnFreeData; LwListInit(&pList->DataList); *ppNewList = pList; pList = NULL; ntError = STATUS_SUCCESS; cleanup: RTL_FREE(&pList); return ntError; error: goto cleanup; }
VOID RdrNotifyContextList( PLW_LIST_LINKS pList, BOOLEAN bLocked, pthread_mutex_t* pMutex, NTSTATUS status, PVOID pParam ) { LW_LIST_LINKS List; PLW_LIST_LINKS pLink = NULL; BOOLEAN bWasLocked = bLocked; LWIO_LOCK_MUTEX(bLocked, pMutex); LwListInit(&List); while ((pLink = LwListRemoveHead(pList))) { LwListInsertTail(&List, pLink); } LWIO_UNLOCK_MUTEX(bLocked, pMutex); RdrContinueContextList(&List, status, pParam); LWIO_LOCK_MUTEX(bLocked, pMutex); while ((pLink = LwListRemoveHead(&List))) { LwListInsertTail(pList, pLink); } if (!bWasLocked) { LWIO_UNLOCK_MUTEX(bLocked, pMutex); } }
LW_NTSTATUS LwIoSetPathCreds( IN LW_PUNICODE_STRING PathPrefix, IN OPTIONAL LW_PIO_CREDS pCreds ) { LW_NTSTATUS Status = STATUS_SUCCESS; PIO_PATH_CREDS pPathCreds = NULL; PIO_CREDS pCredCopy = NULL; BOOL bInLock = FALSE; LWIO_LOCK_MUTEX(bInLock, &gLock); Status = LwIoFindPathCreds(PathPrefix, TRUE, &pPathCreds); BAIL_ON_NT_STATUS(Status); if (pPathCreds) { Status = LwIoCopyCreds(pCreds, &pCredCopy); BAIL_ON_NT_STATUS(Status); if (pPathCreds->pCreds) { LwIoDeleteCreds(pPathCreds->pCreds); } pPathCreds->pCreds = pCredCopy; pCredCopy = NULL; pPathCreds = NULL; } else if (pCreds) { Status = RTL_ALLOCATE(&pPathCreds, IO_PATH_CREDS, sizeof(IO_PATH_CREDS)); BAIL_ON_NT_STATUS(Status); LwListInit(&pPathCreds->link); Status = LwIoNormalizePath(PathPrefix, &pPathCreds->PathPrefix); BAIL_ON_NT_STATUS(Status); Status = LwIoCopyCreds(pCreds, &pPathCreds->pCreds); BAIL_ON_NT_STATUS(Status); LwListInsertBefore(&gPathCreds, &pPathCreds->link); pPathCreds = NULL; } cleanup: LWIO_UNLOCK_MUTEX(bInLock, &gLock); if (pCredCopy) { LwIoDeleteCreds(pCredCopy); } if (pPathCreds) { LwIoDeletePathCreds(pPathCreds); } return Status; error: goto cleanup; }
NTSTATUS IopFileObjectAllocate( OUT PIO_FILE_OBJECT* ppFileObject, IN PIO_DEVICE_OBJECT pDevice, IN PIO_FILE_NAME FileName ) { NTSTATUS status = 0; int EE = 0; PIO_FILE_OBJECT pFileObject = NULL; status = IO_ALLOCATE(&pFileObject, IO_FILE_OBJECT, sizeof(*pFileObject)); GOTO_CLEANUP_ON_STATUS_EE(status, EE); pFileObject->ReferenceCount = 1; pFileObject->pDevice = pDevice; IopDeviceReference(pDevice); LwListInit(&pFileObject->IrpList); LwListInit(&pFileObject->DeviceLinks); LwListInit(&pFileObject->RundownLinks); LwListInit(&pFileObject->ZctCompletionIrpList); // Pre-allocate IRP for close. status = IopIrpCreateDetached(&pFileObject->pCloseIrp); GOTO_CLEANUP_ON_STATUS_EE(status, EE); if (FileName->RootFileHandle) { SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_RELATIVE); } status = LwRtlUnicodeStringDuplicate( &pFileObject->FileName, &FileName->Name); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = LwRtlInitializeMutex(&pFileObject->Mutex, TRUE); GOTO_CLEANUP_ON_STATUS_EE(status, EE); status = LwRtlInitializeConditionVariable(&pFileObject->Rundown.Condition); GOTO_CLEANUP_ON_STATUS_EE(status, EE); IopDeviceLock(pDevice); if (IsSetFlag(pDevice->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN) || IsSetFlag(pDevice->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN_DRIVER)) { // TODO: Find "correct" error code. status = STATUS_INVALID_HANDLE; } else { LwListInsertTail(&pDevice->FileObjectsList, &pFileObject->DeviceLinks); } IopDeviceUnlock(pDevice); cleanup: if (status) { IopFileObjectDereference(&pFileObject); } *ppFileObject = pFileObject; IO_LOG_LEAVE_ON_STATUS_EE(status, EE); return status; }
NTSTATUS RdrTree2Create( PRDR_TREE2* ppTree ) { NTSTATUS status = 0; PRDR_TREE2 pTree = NULL; BOOLEAN bDestroyMutex = FALSE; pthread_mutexattr_t mutexAttr; pthread_mutexattr_t* pMutexAttr = NULL; status = LwIoAllocateMemory( sizeof(RDR_TREE2), (PVOID*)&pTree); BAIL_ON_NT_STATUS(status); LwListInit(&pTree->StateWaiters); status = pthread_mutexattr_init(&mutexAttr); BAIL_ON_NT_STATUS(status); pMutexAttr = &mutexAttr; status = pthread_mutexattr_settype(pMutexAttr, PTHREAD_MUTEX_RECURSIVE); BAIL_ON_NT_STATUS(status); pthread_mutex_init(&pTree->mutex, pMutexAttr); bDestroyMutex = TRUE; /* Pre-allocate resources to send a tree disconnect */ status = RdrCreateContext(NULL, &pTree->pDisconnectContext); BAIL_ON_NT_STATUS(status); status = RdrAllocateContextPacket(pTree->pDisconnectContext, RDR_SMB2_STUB_SIZE); BAIL_ON_NT_STATUS(status); pTree->refCount = 1; pTree->pSession = NULL; pTree->ulTid = 0; pTree->pwszPath = NULL; pTree->version = SMB_PROTOCOL_VERSION_2; *ppTree = pTree; cleanup: if (pMutexAttr) { pthread_mutexattr_destroy(pMutexAttr); } return status; error: if (bDestroyMutex) { pthread_mutex_destroy(&pTree->mutex); } if (pTree) { RdrTree2DestroyContents(pTree); } LWIO_SAFE_FREE_MEMORY(pTree); *ppTree = NULL; goto cleanup; }
BOOLEAN PvfsWildcardMatch( IN PSTR pszPathname, IN PSTR pszPattern, IN BOOLEAN bCaseSensitive ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR pszString = NULL; PSTR pszMatch = NULL; PSTR pszPathUpper = NULL; PSTR pszPatternUpper = NULL; BOOLEAN bMatched = FALSE; LW_LIST_LINKS Stack; // Quick check for an exact match if (!strchr(pszPattern, '?') && !strchr(pszPattern, '*')) { return RtlCStringIsEqual(pszPathname, pszPattern, bCaseSensitive); } // If we have a case insensitive search, upper case the Pathname // and Pattern for easier comparison pszString = pszPathname; pszMatch = pszPattern; if (!bCaseSensitive) { ntError = RtlCStringDuplicate(&pszPathUpper, pszPathname); BAIL_ON_NT_STATUS(ntError); ntError = RtlCStringDuplicate(&pszPatternUpper, pszPattern); BAIL_ON_NT_STATUS(ntError); PvfsCStringUpper(pszPathUpper); PvfsCStringUpper(pszPatternUpper); pszString = pszPathUpper; pszMatch = pszPatternUpper; } // Enter state machine LwListInit(&Stack); reset_state: while (PVFS_CSTRING_NON_NULL(pszString) && PVFS_CSTRING_NON_NULL(pszMatch)) { PVFS_WILDCARD_TYPE eState = 0; CHAR cSrc = '\0'; CHAR cMatch = '\0'; DWORD dwCount = 0; // Save the current CHAR cSrc = *pszString; cMatch = *pszMatch; // Certain characters should never match and hence allow us to filter // certain file patterns if (cSrc == PVFS_STREAM_DELIMINATOR_C) { bMatched = FALSE; goto cleanup; } // Consumes the pattern from pszMatch eState = NextMatchState(&pszMatch, &dwCount); switch (eState) { case PVFS_WILDCARD_TYPE_NONE: if (cSrc != cMatch) { ntError = STATUS_NO_MATCH; pszString = NULL; } else { pszString++; } break; case PVFS_WILDCARD_TYPE_SPLAT: { // We are done if this is the last character in the pattern if (!PVFS_CSTRING_NON_NULL(pszMatch)) { pszString = NULL; } else { // Be greedy - Consume as much of the string using the '*' // as possible. This will require a stack in order to backtrack // on a failure. pszString = PvfsWildcardEatString(pszString, pszMatch); if (!pszString) { ntError = STATUS_NO_MATCH; } else { // Add next character past "String" match and the previously // match "Pattern" state (so we pick up the '*' when we pop // the stack ntError = PvfsWildcardStackPush( &Stack, pszString+1, pszMatch-1); BAIL_ON_NT_STATUS(ntError); } } break; } case PVFS_WILDCARD_TYPE_SINGLE: { DWORD i = 0; // Consume dwCount characters for (i=0; (i<dwCount) && PVFS_CSTRING_NON_NULL(pszString); i++, pszString++) { // no loop body ; } break; } case PVFS_WILDCARD_TYPE_DOT: // For now deal with the '.' as just another character if (cSrc != cMatch) { ntError = STATUS_NO_MATCH; pszString = NULL; } else { pszString++; } break; case PVFS_WILDCARD_TYPE_SPLAT_DOT: { PSTR pszCursor = NULL; // Similar to "A*B" except we search for the '.' from the end if ((pszCursor = strrchr(pszString, '.')) == NULL) { ntError = STATUS_NO_MATCH; pszString = NULL; } else { pszString = pszCursor + 1; } break; } case PVFS_WILDCARD_TYPE_SINGLE_DOT: { DWORD i = 0; // We can match 0 - dwCount characters up to the last '.' // This is really a hold over from DOS 8.3 filenames for (i=0; i<dwCount && PVFS_CSTRING_NON_NULL(pszString) && (*pszString != '.'); i++, pszString++) { // no loop body ; } // If we any path left, it better be on '.' for a match if (*pszString == '.') { pszString++; } else { ntError = STATUS_NO_MATCH; pszString = NULL; } break; } } // end of switch {...} } // end of for {...} // We matched if pszString is empty AND either pszMatch is empty // OR only contains wildcard characters if ((ntError == STATUS_SUCCESS) && !PVFS_CSTRING_NON_NULL(pszString) && (!PVFS_CSTRING_NON_NULL(pszMatch) || PvfsCStringOnlyContainsChars(pszMatch, "?*"))) { bMatched = TRUE; } else if (!LwListIsEmpty(&Stack)) { // Pop back to the earlier state, consume one character (*from '*') // and try another path ntError = PvfsWildcardStackPop(&Stack, &pszString, &pszMatch); BAIL_ON_NT_STATUS(ntError); pszString++; goto reset_state; } cleanup: PvfsWildcardStackDestroy(&Stack); if (!bCaseSensitive) { PVFS_FREE(&pszPathUpper); PVFS_FREE(&pszPatternUpper); } // If we have any string left to parse, we don't have a match return bMatched; error: goto cleanup; }
NTSTATUS IopDeviceRundown( IN PIO_DEVICE_OBJECT pDeviceObject ) { NTSTATUS status = 0; int EE = 0; BOOLEAN isLocked = FALSE; PLW_LIST_LINKS pLinks = NULL; LW_LIST_LINKS rundownList = { 0 }; LwListInit(&rundownList); IopDeviceLock(pDeviceObject); isLocked = TRUE; if (IsSetFlag(pDeviceObject->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN)) { // TODO: Perhaps wait if currently running down. status = STATUS_SUCCESS; GOTO_CLEANUP_EE(EE); } SetFlag(pDeviceObject->Flags, IO_DEVICE_OBJECT_FLAG_RUNDOWN); // Gather rundown list for (pLinks = pDeviceObject->FileObjectsList.Next; pLinks != &pDeviceObject->FileObjectsList; pLinks = pLinks->Next) { PIO_FILE_OBJECT pFileObject = LW_STRUCT_FROM_FIELD(pLinks, IO_FILE_OBJECT, DeviceLinks); IopFileObjectReference(pFileObject); LwListInsertTail(&rundownList, &pFileObject->RundownLinks); } IopDeviceUnlock(pDeviceObject); isLocked = FALSE; // Now, actually run down every file w/o holding the device lock. while (!LwListIsEmpty(&rundownList)) { PIO_FILE_OBJECT pFileObject = NULL; pLinks = LwListRemoveHead(&rundownList); pFileObject = LW_STRUCT_FROM_FIELD(pLinks, IO_FILE_OBJECT, RundownLinks); IopFileObjectRundown(pFileObject); } IopRootRemoveDevice(pDeviceObject->Driver->Root, &pDeviceObject->RootLinks); cleanup: if (isLocked) { IopDeviceUnlock(pDeviceObject); } IO_LOG_LEAVE_ON_STATUS_EE(status, EE); return status; }
VOID IopIrpCancelFileObject( IN PIO_FILE_OBJECT pFileObject, IN BOOLEAN IsForRundown ) { BOOLEAN isLocked = FALSE; PLW_LIST_LINKS pLinks = NULL; PIRP_INTERNAL irpInternal = NULL; LW_LIST_LINKS cancelList = { 0 }; PIRP pIrp = NULL; LwListInit(&cancelList); // Gather IRPs we want to cancel while holding FO lock. IopFileObjectLock(pFileObject); isLocked = TRUE; if (IsSetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CANCELLED)) { GOTO_CLEANUP(); } if (IsForRundown) { SetFlag(pFileObject->Flags, FILE_OBJECT_FLAG_CANCELLED); } // gather list of IRPs for (pLinks = pFileObject->IrpList.Next; pLinks != &pFileObject->IrpList; pLinks = pLinks->Next) { irpInternal = LW_STRUCT_FROM_FIELD(pLinks, IRP_INTERNAL, FileObjectLinks); LWIO_ASSERT(irpInternal->Irp.FileHandle == pFileObject); // Verify that this IRP is not already being cancelled. if (!irpInternal->CancelLinks.Next) { IopIrpReference(&irpInternal->Irp); LwListInsertTail(&cancelList, &irpInternal->CancelLinks); } } IopFileObjectUnlock(pFileObject); isLocked = FALSE; // Iterate over list, calling IopIrpCancel as appropriate. while (!LwListIsEmpty(&cancelList)) { pLinks = LwListRemoveHead(&cancelList); irpInternal = LW_STRUCT_FROM_FIELD(pLinks, IRP_INTERNAL, CancelLinks); pIrp = &irpInternal->Irp; IopIrpCancel(pIrp); IopIrpDereference(&pIrp); } cleanup: if (isLocked) { IopFileObjectUnlock(pFileObject); } }