Esempio n. 1
0
VOID
PvfsInitializeZctSupport(
    IN PPVFS_CCB pCcb,
    IN IO_FILE_HANDLE FileHandle
    )
{
    PVFS_ZCT_MODE ZctMode = gPvfsDriverConfig.ZctMode;
    LW_ZCT_ENTRY_MASK zctReadMask = 0;
    LW_ZCT_ENTRY_MASK zctWriteMask = 0;

    if (!PVFS_IS_DIR(pCcb))
    {
        switch (ZctMode)
        {
        case PVFS_ZCT_MODE_MEMORY:
            zctReadMask = zctWriteMask = LW_ZCT_ENTRY_MASK_MEMORY;
            break;
#ifdef HAVE_SPLICE
        case PVFS_ZCT_MODE_SPLICE:
            zctReadMask = zctWriteMask = LW_ZCT_ENTRY_MASK_FD_PIPE;
            break;
#endif
        default:
            break;
        }

        if (zctReadMask || zctWriteMask)
        {
            IoFileSetZctSupportMask(FileHandle, zctReadMask, zctWriteMask);
        }
    }
}
Esempio n. 2
0
NTSTATUS
PvfsCcbQueryFileStandardInformation(
    PPVFS_CCB pCcb,
    PFILE_STANDARD_INFORMATION pFileInfo
    )
{
    NTSTATUS ntError = STATUS_SUCCESS;
    PVFS_STAT Stat = {0};
    BOOLEAN bDeletePending = FALSE;
    LONG64 allocationSize = 0;

    ntError = PvfsSysFstat(pCcb->fd, &Stat);
    BAIL_ON_NT_STATUS(ntError);

    bDeletePending = PvfsScbIsPendingDelete(pCcb->pScb);

    if (PVFS_IS_DIR(pCcb))
    {
        /* NTFS reports the allocation and end-of-file on
           directories as 0.  smbtorture cares about this even
           if no apps that I know of do. */

        pFileInfo->AllocationSize = 0;
        pFileInfo->EndOfFile      = 0;

        pFileInfo->NumberOfLinks  = bDeletePending ? 0 : 1;
    }
    else
    {
        allocationSize = PvfsGetScbAllocationSize(pCcb->pScb);

        pFileInfo->EndOfFile      = Stat.s_size;
        pFileInfo->AllocationSize = PVFS_MAX((Stat.s_alloc > Stat.s_size ?
                                              Stat.s_alloc : Stat.s_size),
                                             allocationSize);

        pFileInfo->NumberOfLinks  = bDeletePending ?
                                    Stat.s_nlink - 1 :
                                    Stat.s_nlink;
    }

    pFileInfo->DeletePending  = bDeletePending;
    pFileInfo->Directory      = S_ISDIR(Stat.s_mode) ? TRUE : FALSE;

cleanup:

    return ntError;

error:

    goto cleanup;

}
Esempio n. 3
0
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
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;
}
Esempio n. 5
0
NTSTATUS
PvfsRenameCCB(
    IN PPVFS_CCB pCcb,
    IN PPVFS_FILE_NAME pDestFileName
    )
{
    NTSTATUS ntError = STATUS_SUCCESS;
    PVFS_FILE_NAME srcFileName = { 0 };

    ntError = PvfsValidatePathSCB(pCcb->pScb, &pCcb->FileId);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsBuildFileNameFromScb(&srcFileName, pCcb->pScb);
    BAIL_ON_NT_STATUS(ntError);

    if (!PvfsIsDefaultStreamName(&srcFileName) &&
        !PvfsIsDefaultStreamName(pDestFileName))
    {
        // Two named streams
        if (LwRtlCStringIsEqual(
                PvfsGetCStringBaseStreamName(&srcFileName),
                PvfsGetCStringBaseStreamName(pDestFileName),
                FALSE))
        {
            // Both src and dst stream names are the same
            // renaming the underlying file object

            ntError = PvfsRenameFile(pCcb, pDestFileName);
        }
        else if (LwRtlCStringIsEqual(
                     PvfsGetCStringBaseFileName(&srcFileName),
                     PvfsGetCStringBaseFileName(pDestFileName),
                     FALSE))
        {
            // Renaming the named stream, file name stays the same

            ntError = PvfsRenameStream(pCcb, pDestFileName);
        }
        else
        {
            // Don't allow renaming both the file name and stream name at the
            // same time (yet)

            ntError = STATUS_OBJECT_NAME_INVALID;
        }
    }
    else if (PvfsIsDefaultStreamName(&srcFileName) &&
             PvfsIsDefaultStreamName(pDestFileName))
    {
        // Two default streams rename object itself
        ntError = PvfsRenameFile(pCcb, pDestFileName);
    }
    else if (!PvfsIsDefaultStreamName(&srcFileName) &&
             PvfsIsDefaultStreamName(pDestFileName))
    {
        // rename name stream -> default stream
        // A stream on a directory cannot be renamed to the default data stream
        if (!LwRtlCStringIsEqual(
                         PvfsGetCStringBaseFileName(&srcFileName),
                         PvfsGetCStringBaseFileName(pDestFileName),
                         FALSE) || PVFS_IS_DIR(pCcb))
        {
            ntError = STATUS_OBJECT_NAME_INVALID;
        }
        else
        {
            ntError = PvfsRenameStream(pCcb, pDestFileName);
        }
    }
    else
    {
        // disallow rename object->stream as what smbtorture expects
        // TODO:
        // we may want to allow "Renaming" the default data stream
        // it is not a true rename, and it leaves behind a zero-length default data streams
        ntError = STATUS_OBJECT_NAME_INVALID;
    }
    BAIL_ON_NT_STATUS(ntError);

error:
    PvfsDestroyFileName(&srcFileName);

    return ntError;
}
Esempio n. 6
0
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;
}