NTSTATUS PvfsQuerySecurityFile( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_NOT_SUPPORTED; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PSECURITY_DESCRIPTOR_RELATIVE pReturnSecDesc = NULL; ULONG SecDescLength = 0; SECURITY_INFORMATION SecInfo = 0; IRP_ARGS_QUERY_SET_SECURITY Args = pIrpContext->pIrp->Args.QuerySetSecurity; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (!IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_CREATE_COMPLETE)) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } BAIL_ON_INVALID_PTR(Args.SecurityDescriptor, ntError); ntError = PvfsAccessCheckFileHandle(pCcb, READ_CONTROL); BAIL_ON_NT_STATUS(ntError); pReturnSecDesc = Args.SecurityDescriptor; SecDescLength = Args.Length; SecInfo = Args.SecurityInformation; /* Real work starts here */ ntError = PvfsGetSecurityDescriptorFile(pCcb, SecInfo, pReturnSecDesc, &SecDescLength); BAIL_ON_NT_STATUS(ntError); pIrp->IoStatusBlock.BytesTransferred = SecDescLength; ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }
NTSTATUS PvfsReadDirectoryChange( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; IRP_ARGS_READ_DIRECTORY_CHANGE Args = pIrp->Args.ReadDirectoryChange; PPVFS_CCB pCcb = NULL; PULONG pMaxBufferSize = Args.MaxBufferSize; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (!IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_CREATE_COMPLETE)) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } if (!PVFS_IS_DIR(pCcb)) { ntError = STATUS_NOT_A_DIRECTORY; BAIL_ON_NT_STATUS(ntError); } ntError = PvfsAccessCheckFileHandle(pCcb, FILE_LIST_DIRECTORY); BAIL_ON_NT_STATUS(ntError); BAIL_ON_INVALID_PTR(Args.Buffer, ntError); BAIL_ON_ZERO_LENGTH(Args.Length, ntError); /* If we have something in the buffer, return that immediately. Else register a notification filter */ LWIO_ASSERT(pCcb->pScb->pOwnerFcb); ntError = PvfsNotifyReportBufferedChanges( pCcb, pCcb->pScb->pOwnerFcb, pIrpContext); if (ntError == STATUS_NOT_FOUND) { PvfsIrpMarkPending(pIrpContext, PvfsQueueCancelIrp, pIrpContext); LWIO_ASSERT(pCcb->pScb->pOwnerFcb); ntError = PvfsNotifyAddFilter( pCcb->pScb->pOwnerFcb, pIrpContext, pCcb, Args.NotifyFilter, Args.WatchTree, pMaxBufferSize); if (ntError == STATUS_SUCCESS) { pIrpContext->QueueType = PVFS_QUEUE_TYPE_NOTIFY; if (!pIrpContext->pScb) { pIrpContext->pScb = PvfsReferenceSCB(pCcb->pScb); } /* Allow the call to be cancelled while in the queue */ PvfsIrpContextClearFlag(pIrpContext, PVFS_IRP_CTX_FLAG_ACTIVE); ntError = STATUS_PENDING; goto cleanup; } } BAIL_ON_NT_STATUS(ntError); cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: if (PvfsIrpContextCheckFlag(pIrpContext, PVFS_IRP_CTX_FLAG_PENDED)) { pIrpContext->pIrp->IoStatusBlock.Status = ntError; PvfsCompleteIrpContext(pIrpContext); } goto cleanup; }
static NTSTATUS PvfsQueryFileFsAttribInfo( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PFILE_FS_ATTRIBUTE_INFORMATION pFileInfo = NULL; IRP_ARGS_QUERY_SET_VOLUME_INFORMATION Args = pIrpContext->pIrp->Args.QuerySetVolumeInformation; PWSTR pwszFsName = NULL; size_t FsNameLenBytes = RtlCStringNumChars(PVFS_FS_NAME) * sizeof(WCHAR); PVFS_STATFS StatFs = {0}; ULONG FsAttributeSet = PVFS_FILE_SYSTEM_ATTRIBUTES; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); /* not sure exact access rights to check for here */ ntError = PvfsAccessCheckFileHandle(pCcb, FILE_READ_ATTRIBUTES); BAIL_ON_NT_STATUS(ntError); BAIL_ON_INVALID_PTR(Args.FsInformation, ntError); if (Args.Length < sizeof(*pFileInfo) + FsNameLenBytes) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } pFileInfo = (PFILE_FS_ATTRIBUTE_INFORMATION)Args.FsInformation; /* Real work starts here */ ntError = PvfsSysFstatFs(pCcb, &StatFs); BAIL_ON_NT_STATUS(ntError); ntError = RtlWC16StringAllocateFromCString(&pwszFsName, PVFS_FS_NAME); BAIL_ON_NT_STATUS(ntError); pFileInfo->FileSystemAttributes = FsAttributeSet; pFileInfo->MaximumComponentNameLength = StatFs.MaximumNameLength; pFileInfo->FileSystemNameLength = FsNameLenBytes; memcpy(pFileInfo->FileSystemName, pwszFsName, FsNameLenBytes); pIrp->IoStatusBlock.BytesTransferred = sizeof(*pFileInfo); ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } PVFS_FREE(&pwszFsName); return ntError; error: goto cleanup; }
static NTSTATUS PvfsQueryFileIdFullDirInfo( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PFILE_ID_FULL_DIR_INFORMATION pFileInfo = NULL; PFILE_ID_FULL_DIR_INFORMATION pPrevFileInfo = NULL; IRP_ARGS_QUERY_DIRECTORY Args = pIrpContext->pIrp->Args.QueryDirectory; PVOID pBuffer = NULL; DWORD dwBufLen = 0; DWORD dwOffset = 0; DWORD dwConsumed = 0; BOOLEAN bLocked = FALSE; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (!PVFS_IS_DIR(pCcb)) { ntError = STATUS_NOT_A_DIRECTORY; BAIL_ON_NT_STATUS(ntError); } ntError = PvfsAccessCheckFileHandle(pCcb, FILE_LIST_DIRECTORY); BAIL_ON_NT_STATUS(ntError); BAIL_ON_INVALID_PTR(Args.FileInformation, ntError); if (Args.Length < sizeof(*pFileInfo)) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION)Args.FileInformation; /* Scen the first time through */ ntError = STATUS_SUCCESS; /* Critical region to prevent inteleaving directory enumeration */ LWIO_LOCK_MUTEX(bLocked, &pCcb->FileMutex); if (!pCcb->pDirContext->bScanned) { ntError = PvfsEnumerateDirectory( pCcb, pIrp->Args.QueryDirectory.FileSpec, -1, FALSE); } LWIO_UNLOCK_MUTEX(bLocked, &pCcb->FileMutex); BAIL_ON_NT_STATUS(ntError); /* Check for ending condition */ if (pCcb->pDirContext->dwIndex == pCcb->pDirContext->dwNumEntries) { ntError = STATUS_NO_MORE_MATCHES; BAIL_ON_NT_STATUS(ntError); } /* Fill in the buffer */ pBuffer = Args.FileInformation; dwBufLen = Args.Length; dwOffset = 0; pFileInfo = NULL; pPrevFileInfo = NULL; do { PPVFS_DIRECTORY_ENTRY pEntry = NULL; DWORD dwIndex; pFileInfo = (PFILE_ID_FULL_DIR_INFORMATION)(pBuffer + dwOffset); pFileInfo->NextEntryOffset = 0; dwIndex = pCcb->pDirContext->dwIndex; pEntry = &pCcb->pDirContext->pDirEntries[dwIndex]; ntError = FillFileIdFullDirInfoBuffer( pFileInfo, dwBufLen - dwOffset, pCcb->pszFilename, pEntry, &dwConsumed); /* If we ran out of buffer space, reset pointer to previous entry and break out of loop */ if (ntError == STATUS_BUFFER_TOO_SMALL) { pFileInfo = pPrevFileInfo; break; } /* OBJECT_NAME_NOT_FOUND - This deals with a possible race where the directory contents was read but the file was removed before we could stat() it. INSUFFICIENT_RESOURCES - Invalid UTF-8 name. ACCESS_DENIED - Special cases like $HOME/.gvfs that can't be read by root. Possibly just an Ubuntu bug but don't fail on it. https://bugs.launchpad.net/ubuntu/+source/gvfs/+bug/227724 Just skip the file and move on. */ if (ntError == STATUS_OBJECT_NAME_NOT_FOUND || ntError == STATUS_INSUFFICIENT_RESOURCES || ntError == STATUS_ACCESS_DENIED) { pFileInfo = pPrevFileInfo; pCcb->pDirContext->dwIndex++; continue; } /* Catch any other errors and bail */ BAIL_ON_NT_STATUS(ntError); pFileInfo->NextEntryOffset = dwConsumed; dwOffset += dwConsumed; pCcb->pDirContext->dwIndex++; pPrevFileInfo = pFileInfo; if (Args.ReturnSingleEntry) { break; } } /* Exit loop when we are out of buffer or out of entries. The filling function can also break us out of the loop. */ while (((dwBufLen - dwOffset) > sizeof(FILE_ID_FULL_DIR_INFORMATION)) && (pCcb->pDirContext->dwIndex < pCcb->pDirContext->dwNumEntries)); /* Update final offset */ if (pFileInfo) { pFileInfo->NextEntryOffset = 0; } pIrp->IoStatusBlock.BytesTransferred = dwOffset; ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }
static NTSTATUS PvfsSetFileAllocationInfo( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; IRP_ARGS_QUERY_SET_INFORMATION Args = {0}; PPVFS_PENDING_SET_ALLOCATION pSetAllocationCtx = NULL; PFILE_ALLOCATION_INFORMATION pFileInfo = NULL; Args = pIrpContext->pIrp->Args.QuerySetInformation; pFileInfo = (PFILE_ALLOCATION_INFORMATION)Args.FileInformation; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); BAIL_ON_INVALID_PTR(Args.FileInformation, ntError); if (Args.Length < sizeof(*pFileInfo)) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } ntError = PvfsAccessCheckFileHandle(pCcb, FILE_WRITE_DATA); BAIL_ON_NT_STATUS(ntError); ntError = PvfsCreateSetAllocationContext( &pSetAllocationCtx, pIrpContext, pCcb); BAIL_ON_NT_STATUS(ntError); ntError = PvfsOplockBreakIfLocked(pIrpContext, pCcb, pCcb->pFcb); switch (ntError) { case STATUS_SUCCESS: ntError = PvfsSetAllocationWithContext(pSetAllocationCtx); break; case STATUS_OPLOCK_BREAK_IN_PROGRESS: ntError = PvfsPendOplockBreakTest( pSetAllocationCtx->pCcb->pFcb, pIrpContext, pSetAllocationCtx->pCcb, PvfsSetAllocationWithContext, PvfsFreeSetAllocationContext, (PVOID)pSetAllocationCtx); if (ntError == STATUS_SUCCESS) { pSetAllocationCtx = NULL; ntError = STATUS_PENDING; } break; case STATUS_PENDING: ntError = PvfsAddItemPendingOplockBreakAck( pSetAllocationCtx->pCcb->pFcb, pIrpContext, PvfsSetAllocationWithContext, PvfsFreeSetAllocationContext, (PVOID)pSetAllocationCtx); if (ntError == STATUS_SUCCESS) { pSetAllocationCtx = NULL; ntError = STATUS_PENDING; } break; } BAIL_ON_NT_STATUS(ntError); cleanup: PvfsFreeSetAllocationContext((PVOID*)&pSetAllocationCtx); if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }
NTSTATUS PvfsSetSecurityFile( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_ACCESS_DENIED; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PSECURITY_DESCRIPTOR_RELATIVE pSecDesc = NULL; ULONG SecDescLength = 0; SECURITY_INFORMATION SecInfo = 0; IRP_ARGS_QUERY_SET_SECURITY Args = pIrpContext->pIrp->Args.QuerySetSecurity; ACCESS_MASK RequiredMask = 0; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (!IsSetFlag(pCcb->Flags, PVFS_CCB_FLAG_CREATE_COMPLETE)) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } BAIL_ON_INVALID_PTR(Args.SecurityDescriptor, ntError); pSecDesc = Args.SecurityDescriptor; SecDescLength = Args.Length; SecInfo = Args.SecurityInformation; if (SecInfo & OWNER_SECURITY_INFORMATION) { RequiredMask |= WRITE_OWNER; } if (SecInfo & GROUP_SECURITY_INFORMATION) { RequiredMask |= WRITE_OWNER; } if (SecInfo & DACL_SECURITY_INFORMATION) { RequiredMask |= WRITE_DAC; } if (SecInfo & SACL_SECURITY_INFORMATION) { RequiredMask |= ACCESS_SYSTEM_SECURITY; } ntError = PvfsAccessCheckFileHandle(pCcb, RequiredMask); BAIL_ON_NT_STATUS(ntError); /* Real work starts here */ ntError = PvfsSetSecurityDescriptorFile(pCcb, SecInfo, pSecDesc, SecDescLength); BAIL_ON_NT_STATUS(ntError); pIrp->IoStatusBlock.BytesTransferred = 0; ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }
static NTSTATUS PvfsQueryFileFsVolInfo( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PFILE_FS_VOLUME_INFORMATION pFileInfo = NULL; IRP_ARGS_QUERY_SET_VOLUME_INFORMATION Args = pIrpContext->pIrp->Args.QuerySetVolumeInformation; PWSTR pwszVolumeName = NULL; PCSTR pszVolName = "LIKEWISE"; size_t VolNameLenBytes = RtlCStringNumChars(pszVolName) * sizeof(WCHAR); PVFS_STAT stat = { 0 }; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); /* not sure exact access rights to check for here */ ntError = PvfsAccessCheckFileHandle(pCcb, FILE_READ_ATTRIBUTES); BAIL_ON_NT_STATUS(ntError); BAIL_ON_INVALID_PTR(Args.FsInformation, ntError); if (Args.Length < sizeof(*pFileInfo) + VolNameLenBytes) { ntError = STATUS_BUFFER_TOO_SMALL; BAIL_ON_NT_STATUS(ntError); } pFileInfo = (PFILE_FS_VOLUME_INFORMATION)Args.FsInformation; /* Real work starts here */ ntError = PvfsSysFstat(pCcb->fd, &stat); BAIL_ON_NT_STATUS(ntError); ntError = PvfsUnixToWinTime(&pFileInfo->VolumeCreationTime, stat.s_crtime); BAIL_ON_NT_STATUS(ntError); pFileInfo->VolumeSerialNumber = 0x009a9a03; pFileInfo->SupportsObjects = FALSE; ntError = RtlWC16StringAllocateFromCString(&pwszVolumeName, pszVolName); BAIL_ON_NT_STATUS(ntError); pFileInfo->VolumeLabelLength = VolNameLenBytes; memcpy(pFileInfo->VolumeLabel, pwszVolumeName, VolNameLenBytes); pIrp->IoStatusBlock.BytesTransferred = sizeof(*pFileInfo); ntError = STATUS_SUCCESS; cleanup: if (pCcb) { PvfsReleaseCCB(pCcb); } PVFS_FREE(&pwszVolumeName); return ntError; error: goto cleanup; }
static NTSTATUS PvfsReadInternal( PPVFS_IRP_CONTEXT pIrpContext ) { NTSTATUS ntError = STATUS_UNSUCCESSFUL; PIRP pIrp = pIrpContext->pIrp; PPVFS_CCB pCcb = NULL; PPVFS_PENDING_READ pReadCtx = NULL; /* Sanity checks */ ntError = PvfsAcquireCCB(pIrp->FileHandle, &pCcb); BAIL_ON_NT_STATUS(ntError); if (PVFS_IS_DIR(pCcb)) { ntError = STATUS_FILE_IS_A_DIRECTORY; BAIL_ON_NT_STATUS(ntError); } #if 0xFFFFFFFF > SSIZE_MAX if ((size_t)pIrp->Args.ReadWrite.Length > (size_t) SSIZE_MAX) { ntError = STATUS_INVALID_PARAMETER; BAIL_ON_NT_STATUS(ntError); } #endif /* Check the right permissions based on the PagingIo flag */ if (pIrp->Args.ReadWrite.IsPagingIo) { ntError = PvfsAccessCheckAnyFileHandle( pCcb, FILE_READ_DATA|FILE_EXECUTE); } else { ntError = PvfsAccessCheckFileHandle( pCcb, FILE_READ_DATA); } BAIL_ON_NT_STATUS(ntError); ntError = PvfsCreateReadContext(&pReadCtx, pIrpContext, pCcb); BAIL_ON_NT_STATUS(ntError); ntError = PvfsOplockBreakIfLocked(pIrpContext, pCcb, pCcb->pScb); switch (ntError) { case STATUS_SUCCESS: ntError = PvfsReadFileWithContext(pReadCtx); break; case STATUS_OPLOCK_BREAK_IN_PROGRESS: ntError = PvfsPendOplockBreakTest( pReadCtx->pCcb->pScb, pIrpContext, pReadCtx->pCcb, PvfsReadFileWithContext, PvfsFreeReadContext, (PVOID)pReadCtx); if (ntError == STATUS_PENDING) { pReadCtx = NULL; } break; case STATUS_PENDING: ntError = PvfsAddItemPendingOplockBreakAck( pReadCtx->pCcb->pScb, pIrpContext, PvfsReadFileWithContext, PvfsFreeReadContext, (PVOID)pReadCtx); if (ntError == STATUS_PENDING) { pReadCtx = NULL; } break; } BAIL_ON_NT_STATUS(ntError); cleanup: PvfsFreeReadContext(OUT_PPVOID(&pReadCtx)); if (pCcb) { PvfsReleaseCCB(pCcb); } return ntError; error: goto cleanup; }