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; }
NTSTATUS LwRtlAnsiStringAllocateFromUnicodeString( OUT PANSI_STRING pNewString, IN PUNICODE_STRING pString ) { NTSTATUS status = 0; PSTR pszNewString = NULL; ANSI_STRING newString = { 0 }; status = RtlCStringDuplicate(&pszNewString, pszString); GOTO_CLEANUP_ON_STATUS(status); newString.Buffer = pszNewString; pszNewString = 0; newString.Length = wc16slen(newString.Buffer) * sizeof(newString.Buffer[0]); newString.MaximumLength = newString.Length + sizeof(newString.Buffer[0]); cleanup: if (status) { RtlCStringFree(&pszNewString); RtlAnsiStringFree(&newString); } *pString = newString; return status; }
NTSTATUS LwRtlAnsiStringAllocateFromCString( OUT PANSI_STRING pNewString, IN PCSTR pszString ) { NTSTATUS status = 0; PSTR pszNewString = NULL; ANSI_STRING newString = { 0 }; status = RtlCStringDuplicate(&pszNewString, pszString); GOTO_CLEANUP_ON_STATUS(status); status = LwRtlAnsiStringInitEx(&newString, pszNewString); GOTO_CLEANUP_ON_STATUS(status); pszNewString = 0; cleanup: if (status) { RtlCStringFree(&pszNewString); RtlAnsiStringFree(&newString); } *pNewString = newString; return status; }
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; }
NTSTATUS PvfsLookupFile( PSTR *ppszDiskPath, PCSTR pszDiskDirname, PCSTR pszFilename, BOOLEAN bCaseSensitive ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PSTR pszFullPath = NULL; ntError = RtlCStringAllocatePrintf(&pszFullPath, "%s/%s", pszDiskDirname, pszFilename); BAIL_ON_NT_STATUS(ntError); ntError = PvfsLookupPath(ppszDiskPath, pszFullPath, bCaseSensitive); BAIL_ON_NT_STATUS(ntError); cleanup: RtlCStringFree(&pszFullPath); return ntError; error: goto cleanup; }
VOID PvfsFreeDirectoryContext( PPVFS_DIRECTORY_CONTEXT pDirCtx ) { int i = 0; if (!pDirCtx) { return; } for (i=0; i<pDirCtx->dwNumEntries; i++) { RtlCStringFree(&pDirCtx->pDirEntries[i].pszFilename); } PVFS_FREE(&pDirCtx->pDirEntries); PVFS_FREE(&pDirCtx); return; }
NTSTATUS PvfsCreate( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; FILE_CREATE_OPTIONS CreateOptions = 0; BOOLEAN bIsDirectory = FALSE; PIRP pIrp = pIrpContext->pIrp; PSTR pszFilename = NULL; PSTR pszDiskFilename = NULL; PVFS_STAT Stat = {0}; FILE_CREATE_OPTIONS FileDirCombo = (FILE_DIRECTORY_FILE| FILE_NON_DIRECTORY_FILE); /* Check to see if this is a Device Create (i.e. NULL RootFileHandle and empty Filename) */ if (!pIrp->Args.Create.FileName.RootFileHandle && pIrp->Args.Create.FileName.FileName && *pIrp->Args.Create.FileName.FileName == '\0') { ntError = PvfsCreateDevice(pIrpContext); BAIL_ON_NT_STATUS(ntError); goto cleanup; } /* Regular File/Directory Create() */ CreateOptions = pIrp->Args.Create.CreateOptions; if (((CreateOptions & ~FILE_CREATE_OPTIONS_VALID) != 0)) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } if ((CreateOptions & FileDirCombo) == FileDirCombo) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } if (CreateOptions & FILE_DIRECTORY_FILE) { bIsDirectory = TRUE; } else if (CreateOptions & FILE_NON_DIRECTORY_FILE) { bIsDirectory = FALSE; } else { /* stat() the path and find out if this is a file or directory */ ntError = PvfsCanonicalPathName( &pszFilename, pIrp->Args.Create.FileName); BAIL_ON_NT_STATUS(ntError); ntError = PvfsLookupPath(&pszDiskFilename, pszFilename, FALSE); /* The path lookup may fail which is ok. We'll catch whether or not this is a real error later on */ if (ntError == STATUS_SUCCESS) { ntError = PvfsSysStat(pszDiskFilename, &Stat); bIsDirectory = (ntError == STATUS_SUCCESS) ? S_ISDIR(Stat.s_mode) : FALSE; } } if (bIsDirectory) { pIrp->Args.Create.CreateOptions |= FILE_DIRECTORY_FILE; ntError = PvfsCreateDirectory(pIrpContext); } /* File branch */ else { pIrp->Args.Create.CreateOptions |= FILE_NON_DIRECTORY_FILE; ntError = PvfsCreateFile(pIrpContext); } BAIL_ON_NT_STATUS(ntError); ntError = PvfsSetMaximalAccessMask(pIrp); BAIL_ON_NT_STATUS(ntError); cleanup: RtlCStringFree(&pszFilename); RtlCStringFree(&pszDiskFilename); return ntError; error: goto cleanup; }
static NTSTATUS FillFileIdFullDirInfoBuffer( PVOID pBuffer, DWORD dwBufLen, PSTR pszParent, PPVFS_DIRECTORY_ENTRY pEntry, PDWORD pdwConsumed ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PFILE_ID_FULL_DIR_INFORMATION pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION)pBuffer; PWSTR pwszFilename = NULL; PSTR pszFullPath = NULL; DWORD dwNeeded = 0; size_t W16FilenameLen = 0; size_t W16FilenameLenBytes = 0; /* Check for enough space for static members */ if (dwBufLen < sizeof(*pFileInfo)) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } /* Build the absolute path and stat() it */ ntError = RtlCStringAllocatePrintf( &pszFullPath, "%s/%s", pszParent, pEntry->pszFilename); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSysStat(pszFullPath, &pEntry->Stat); BAIL_ON_NT_STATUS(ntError); ntError = RtlWC16StringAllocateFromCString( &pwszFilename, pEntry->pszFilename); BAIL_ON_NT_STATUS(ntError); ntError = FillFileIdFullDirInfoStatic( pFileInfo, pwszFilename, &pEntry->Stat); BAIL_ON_NT_STATUS(ntError); /* We have more information here to fill in the file attributes */ ntError = PvfsGetFilenameAttributes( pszFullPath, &pFileInfo->FileAttributes); BAIL_ON_NT_STATUS(ntError); /* Save what we have used so far */ *pdwConsumed = sizeof(*pFileInfo); /* Calculate space */ W16FilenameLen = RtlWC16StringNumChars(pwszFilename); W16FilenameLenBytes = W16FilenameLen * sizeof(WCHAR); dwNeeded = sizeof(*pFileInfo) + W16FilenameLenBytes; /* alignment on 8 byte boundary */ if (dwNeeded % 8) { dwNeeded += 8 - (dwNeeded % 8); } if (dwNeeded > dwBufLen) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } pFileInfo->FileNameLength = W16FilenameLenBytes; memcpy(pFileInfo->FileName, pwszFilename, W16FilenameLenBytes); *pdwConsumed = dwNeeded; ntError = STATUS_SUCCESS; cleanup: RtlCStringFree(&pszFullPath); RtlWC16StringFree(&pwszFilename); return ntError; error: goto cleanup; }
static NTSTATUS PvfsResolvePath( PSTR *ppszResolvedPath, PCSTR pszLookupPath ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR pszCursor = NULL; PSTR pszComponent = NULL; PSTR pszPath = NULL; PVFS_STAT Stat = {0}; PSTR pszResolvedPath = NULL; PSTR pszResWorkingPath = NULL; PSTR pszWorkingPath = NULL; DWORD Length = PATH_MAX; DIR *pDir = NULL; struct dirent *pDirEntry = NULL; if (*pszLookupPath != '/') { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } ntError = RTL_ALLOCATE(&pszResolvedPath, CHAR, Length); BAIL_ON_NT_STATUS(ntError); ntError = RTL_ALLOCATE(&pszWorkingPath, CHAR, PATH_MAX); BAIL_ON_NT_STATUS(ntError); ntError = RtlCStringDuplicate(&pszPath, pszLookupPath); BAIL_ON_NT_STATUS(ntError); pszComponent = pszPath + 1; while (pszComponent && (Length > 0)) { pDir = NULL; if ((pszCursor = strchr(pszComponent, '/')) != NULL) { *pszCursor = '\0'; } snprintf(pszWorkingPath, PATH_MAX-1, "%s/%s", pszResolvedPath, pszComponent); /* Try cache first */ ntError = PvfsPathCacheLookup(&pszResWorkingPath, pszWorkingPath); if(ntError == STATUS_SUCCESS) { strncpy(pszResolvedPath, pszResWorkingPath, PATH_MAX-1); Length = PATH_MAX - RtlCStringNumChars(pszResolvedPath); RtlCStringFree(&pszResWorkingPath); } /* Maybe an exact match on disk? */ else if (PvfsSysStat(pszWorkingPath, &Stat) == STATUS_SUCCESS) { strncpy(pszResolvedPath, pszWorkingPath, PATH_MAX-1); Length = PATH_MAX - RtlCStringNumChars(pszResolvedPath); RtlCStringFree(&pszResWorkingPath); ntError = PvfsPathCacheAdd(pszResolvedPath); BAIL_ON_NT_STATUS(ntError); } /* Do the work ourselves */ else { /* Enumerate directory entries and look for a match */ ntError = PvfsSysOpenDir(pszResolvedPath, &pDir); if (ntError == STATUS_NOT_A_DIRECTORY) { ntError = STATUS_OBJECT_PATH_NOT_FOUND; } BAIL_ON_NT_STATUS(ntError); for(ntError = PvfsSysReadDir(pDir, &pDirEntry); pDirEntry; ntError = PvfsSysReadDir(pDir, &pDirEntry)) { /* First check the error return */ BAIL_ON_NT_STATUS(ntError); if (RtlCStringIsEqual(pszComponent, pDirEntry->d_name, FALSE)) { break; } } /* Did we find a match? */ if (!pDirEntry) { /* Return code depends on whether the last component was not found or if an intermediate component was invalid */ if (pszCursor == NULL) { ntError = STATUS_OBJECT_NAME_NOT_FOUND; } else { ntError = STATUS_OBJECT_PATH_NOT_FOUND; } BAIL_ON_NT_STATUS(ntError); } strncat(pszResolvedPath, "/", Length-1); Length -= 1; strncat(pszResolvedPath, pDirEntry->d_name, Length-1); Length -= RtlCStringNumChars(pDirEntry->d_name); ntError = PvfsSysCloseDir(pDir); pDir = NULL; BAIL_ON_NT_STATUS(ntError); ntError = PvfsPathCacheAdd(pszResolvedPath); BAIL_ON_NT_STATUS(ntError); } /* Cleanup for next loop */ if (pszCursor) { *pszCursor = '/'; } if ((pszComponent = strchr(pszComponent, '/')) != NULL) { pszComponent++; } } /* Did we finish? */ if ((Length <= 0) && (pszComponent != NULL)) { ntError = STATUS_NAME_TOO_LONG; BAIL_ON_NT_STATUS(ntError); } *ppszResolvedPath = pszResolvedPath; pszResolvedPath = NULL; ntError = STATUS_SUCCESS; cleanup: RtlCStringFree(&pszPath); RtlCStringFree(&pszWorkingPath); RtlCStringFree(&pszResWorkingPath); RtlCStringFree(&pszResolvedPath); if (pDir) { PvfsSysCloseDir(pDir); } return ntError; error: goto cleanup; }
NTSTATUS PvfsEnumerateDirectory( PPVFS_CCB pCcb, PIO_MATCH_FILE_SPEC pFileSpec, LONG Count, BOOLEAN bRescan ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; DIR *pDir = NULL; struct dirent *pDirEntry = NULL; struct dirent dirEntry = { 0 }; PSTR pszPattern = NULL; BOOLEAN bCaseSensitive = FALSE; PSTR pszDiskFilename = NULL; PVFS_STAT Stat = { 0 }; PSTR pszResolvedDirname = NULL; PSTR pszResolvedFilename = NULL; if (Count == 0) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } ntError = AllocateCStringFileSpec(&pszPattern, pFileSpec); BAIL_ON_NT_STATUS(ntError); if (bRescan) { if (pCcb->pDirContext->pDir) { PvfsSysCloseDir(pCcb->pDirContext->pDir); } PvfsFreeDirectoryContext(pCcb->pDirContext); pCcb->pDirContext = NULL; ntError = PvfsAllocateMemory( (PVOID)&pCcb->pDirContext, sizeof(PVFS_DIRECTORY_CONTEXT), TRUE); BAIL_ON_NT_STATUS(ntError); pCcb->pDirContext->bScanned = FALSE; } if (!pCcb->pDirContext->bScanned) { if (!strchr(pszPattern, '?') && !strchr(pszPattern, '*')) { // A single file name match is the equivalent of a Windows Stat() ntError = PvfsLookupFile( &pszDiskFilename, &Stat, pCcb->pScb->pOwnerFcb->pszFilename, pszPattern, pFileSpec->Options & IO_NAME_OPTION_CASE_SENSITIVE); BAIL_ON_NT_STATUS(ntError); ntError = PvfsFileSplitPath( &pszResolvedDirname, &pszResolvedFilename, pszDiskFilename); BAIL_ON_NT_STATUS(ntError); if (IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_ENABLE_ABE)) { ntError = PvfsAccessCheckFileEnumerate( pCcb, pszResolvedFilename); BAIL_ON_NT_STATUS(ntError); } ntError = PvfsDirContextAddEntry( pCcb->pDirContext, pszResolvedFilename); BAIL_ON_NT_STATUS(ntError); pCcb->pDirContext->bScanned = TRUE; // Success goto cleanup; } else { // Prepare to enumerate the entire directory ntError = PvfsSysOpenDir( pCcb->pScb->pOwnerFcb->pszFilename, &pCcb->pDirContext->pDir); BAIL_ON_NT_STATUS(ntError); pCcb->pDirContext->bScanned = TRUE; } } /* Loop to read entries */ pDir = pCcb->pDirContext->pDir; /* -1 means to fill in whatever you can including current and parent directory entries */ if (Count == -1) { /* Always add '.' and '..' first if thet match */ if (PvfsWildcardMatch(".", pszPattern, FALSE)) { ntError = PvfsDirContextAddEntry(pCcb->pDirContext, "."); BAIL_ON_NT_STATUS(ntError); } if (PvfsWildcardMatch("..", pszPattern, FALSE)) { ntError = PvfsDirContextAddEntry(pCcb->pDirContext, ".."); BAIL_ON_NT_STATUS(ntError); } } /* Loop through directory entries */ for(ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry); pDirEntry && ((Count == -1) || (pCcb->pDirContext->dwNumEntries < Count)); ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry)) { /* First check the error return */ BAIL_ON_NT_STATUS(ntError); /* We've already added the "." and ".." directories */ if (RtlCStringIsEqual(pDirEntry->d_name, ".", FALSE) || RtlCStringIsEqual(pDirEntry->d_name, "..", FALSE)) { continue; } if (PvfsWildcardMatch(pDirEntry->d_name, pszPattern, bCaseSensitive)) { if (IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_ENABLE_ABE)) { ntError = PvfsAccessCheckFileEnumerate( pCcb, pDirEntry->d_name); if (ntError != STATUS_SUCCESS) { continue; } } ntError = PvfsDirContextAddEntry(pCcb->pDirContext, pDirEntry->d_name); BAIL_ON_NT_STATUS(ntError); } } /* Bail if there were no matches */ if (pCcb->pDirContext->dwNumEntries == 0) { ntError = STATUS_NO_SUCH_FILE; BAIL_ON_NT_STATUS(ntError); } cleanup: RtlCStringFree(&pszResolvedFilename); RtlCStringFree(&pszResolvedDirname); RtlCStringFree(&pszDiskFilename); RtlCStringFree(&pszPattern); return ntError; error: goto cleanup; }
NTSTATUS PvfsCreateFileSecurity( PACCESS_TOKEN pUserToken, PPVFS_CCB pCcb, PSECURITY_DESCRIPTOR_RELATIVE pSecurityDescriptor, BOOLEAN bIsDirectory ) { NTSTATUS ntError = STATUS_SUCCESS; PSTR pszParentPath = NULL; PSTR pszBaseFilename = NULL; PSECURITY_DESCRIPTOR_RELATIVE pFinalSecDesc = NULL; ULONG FinalSecDescLength = 0; BYTE ParentSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG ParentSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; SECURITY_INFORMATION SecInfoAll = (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION); BYTE DefaultSecDescBuffer[SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE]; ULONG DefaultSecDescLength = SECURITY_DESCRIPTOR_RELATIVE_MAX_SIZE; LwRtlZeroMemory(ParentSecDescBuffer, ParentSecDescLength); LwRtlZeroMemory(DefaultSecDescBuffer, DefaultSecDescLength); ntError = PvfsFileSplitPath( &pszParentPath, &pszBaseFilename, pCcb->pszFilename); BAIL_ON_NT_STATUS(ntError); ntError = PvfsGetSecurityDescriptorFilename( pszParentPath, SecInfoAll, (PSECURITY_DESCRIPTOR_RELATIVE)ParentSecDescBuffer, &ParentSecDescLength); BAIL_ON_NT_STATUS(ntError); ntError = RtlCreatePrivateObjectSecurityEx( (PSECURITY_DESCRIPTOR_RELATIVE)ParentSecDescBuffer, pSecurityDescriptor, &pFinalSecDesc, &FinalSecDescLength, NULL, bIsDirectory, SEF_DACL_AUTO_INHERIT|SEF_SACL_AUTO_INHERIT, pUserToken, &gPvfsFileGenericMapping); BAIL_ON_NT_STATUS(ntError); ntError = PvfsSetSecurityDescriptorFile( pCcb, SecInfoAll, pFinalSecDesc, FinalSecDescLength); BAIL_ON_NT_STATUS(ntError); cleanup: LW_RTL_FREE(&pFinalSecDesc); RtlCStringFree(&pszParentPath); RtlCStringFree(&pszBaseFilename); return ntError; error: goto cleanup; }