static VOID
PvfsFreeSetAllocationContext(
    IN OUT PVOID *ppContext
    )
{
    PPVFS_PENDING_SET_ALLOCATION pAllocationCtx = NULL;

    if (ppContext && ppContext)
    {
        pAllocationCtx = (PPVFS_PENDING_SET_ALLOCATION)(*ppContext);

        if (pAllocationCtx->pIrpContext)
        {
            PvfsReleaseIrpContext(&pAllocationCtx->pIrpContext);
        }

        if (pAllocationCtx->pCcb)
        {
            PvfsReleaseCCB(pAllocationCtx->pCcb);
        }

        PVFS_FREE(ppContext);
    }

    return;
}
Example #2
0
static
VOID
PvfsFreeSetEndOfFileContext(
    IN OUT PVOID *ppContext
    )
{
    PPVFS_PENDING_SET_END_OF_FILE pEoFCtx = NULL;

    if (ppContext && *ppContext)
    {
        pEoFCtx = (PPVFS_PENDING_SET_END_OF_FILE)(*ppContext);

        if (pEoFCtx->pIrpContext)
        {
            PvfsReleaseIrpContext(&pEoFCtx->pIrpContext);
        }

        if (pEoFCtx->pCcb)
        {
            PvfsReleaseCCB(pEoFCtx->pCcb);
        }

        PVFS_FREE(ppContext);
    }

    return;
}
Example #3
0
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;
}
Example #4
0
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);
    }
}
Example #5
0
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;
}
Example #6
0
VOID
PvfsFreeNotifyRecord(
    PPVFS_NOTIFY_FILTER_RECORD *ppNotifyRecord
    )
{
    PPVFS_NOTIFY_FILTER_RECORD pFilter = NULL;

    if (ppNotifyRecord && *ppNotifyRecord)
    {
        pFilter = *ppNotifyRecord;

        if (pFilter->pIrpContext)
        {
            PvfsReleaseIrpContext(&pFilter->pIrpContext);
        }

        PvfsNotifyFreeChangeBuffer(&pFilter->Buffer);

        if (pFilter->pCcb)
        {
            PvfsReleaseCCB(pFilter->pCcb);
        }

        PVFS_FREE(ppNotifyRecord);
    }

    return;
}
Example #7
0
static
VOID
PvfsFreeReadContext(
    IN OUT PVOID *ppContext
    )
{
    PPVFS_PENDING_READ pReadCtx = NULL;

    if (ppContext && *ppContext)
    {
        pReadCtx = (PPVFS_PENDING_READ)(*ppContext);

        if (pReadCtx->pZctContext)
        {
            PvfsFreeZctContext(&pReadCtx->pZctContext);
        }

        if (pReadCtx->pIrpContext)
        {
            PvfsReleaseIrpContext(&pReadCtx->pIrpContext);
        }

        if (pReadCtx->pCcb)
        {
            PvfsReleaseCCB(pReadCtx->pCcb);
        }

        PVFS_FREE(ppContext);
    }

    return;
}
Example #8
0
VOID
PvfsFreeZctContext(
    IN OUT PPVFS_ZCT_CONTEXT *ppZctContext
    )
{
    PPVFS_ZCT_CONTEXT pZctContext = *ppZctContext;

    // pZctContext->pCcb must be locked if the context
    // is in the CCB list of ZCT contexts.

    if (pZctContext)
    {
        switch (pZctContext->Mode)
        {
        case PVFS_ZCT_MODE_MEMORY:
            PVFS_FREE(&pZctContext->pBuffer);
            break;
#ifdef HAVE_SPLICE
        case PVFS_ZCT_MODE_SPLICE:
            if (pZctContext->PipeFds[1] >= 0)
            {
                PvfsSysClose(pZctContext->PipeFds[1]);
            }

            if (pZctContext->PipeFds[0] >= 0)
            {
                PvfsSysClose(pZctContext->PipeFds[0]);
            }
            break;
#endif
        default:
            // can never happen
            break;
        }
        if (pZctContext->pCcb)
        {
            PvfsReleaseCCB(pZctContext->pCcb);
            if (pZctContext->CcbLinks.Next)
            {
                PvfsListRemoveItem(
                    pZctContext->pCcb->pZctContextList,
                    &pZctContext->CcbLinks);
            }
        }
        PVFS_FREE(ppZctContext);
    }
}
Example #9
0
static
VOID
PvfsNotifyFreeChangeBuffer(
    PPVFS_NOTIFY_FILTER_BUFFER pBuffer
    )
{
    PVFS_FREE(&pBuffer->pData);

    PVFS_ZERO_MEMORY(pBuffer);
}
Example #10
0
NTSTATUS
PvfsFreeCCB(
    PPVFS_CCB pCCB
    )
{
    LWIO_ASSERT(pCCB->RefCount == 0);

    if (pCCB->pScb)
    {
        PvfsRemoveCCBFromSCB(pCCB->pScb, pCCB);
        PvfsReleaseSCB(&pCCB->pScb);
    }

    if (pCCB->pDirContext)
    {
        PvfsFreeDirectoryContext(pCCB->pDirContext);
    }

    if (pCCB->pUserToken)
    {
        RtlReleaseAccessToken(&pCCB->pUserToken);
        pCCB->pUserToken = NULL;
    }

    PvfsListDestroy(&pCCB->pZctContextList);

    LwRtlWC16StringFree(&pCCB->pwszShareName);

    PVFS_FREE(&pCCB->LockTable.ExclusiveLocks.pLocks);
    PVFS_FREE(&pCCB->LockTable.SharedLocks.pLocks);

    pthread_mutex_destroy(&pCCB->ControlBlock);

    PVFS_FREE(&pCCB);

    InterlockedDecrement(&gPvfsDriverState.Counters.Ccb);

    return STATUS_SUCCESS;
}
Example #11
0
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;
}
Example #12
0
VOID
PvfsListDestroy(
    PPVFS_LIST *ppList
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    PPVFS_LIST pList = NULL;
    PLW_LIST_LINKS pData = NULL;

    if (ppList && *ppList)
    {
        pList = *ppList;

        while (!PvfsListIsEmpty(pList))
        {
            pData = NULL;

            ntError = PvfsListRemoveHead(pList, &pData);

            /* Avoid an infinite loop in the case of
               an error.  This means we may leak memory. */
            BAIL_ON_NT_STATUS(ntError);

            if (pList->pfnFreeData)
            {
                pList->pfnFreeData((PVOID*)&pData);
            }
            else
            {
                PVFS_FREE(&pData);
            }
        }

        RTL_FREE(ppList);
    }

cleanup:
    return;

error:
    goto cleanup;
}
Example #13
0
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;
}
Example #14
0
BOOLEAN
PvfsWildcardMatch(
    IN PSTR pszPathname,
    IN PSTR pszPattern,
    IN BOOLEAN bCaseSensitive
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    PSTR pszString = NULL;
    PSTR pszMatch  = NULL;
    PSTR pszPathUpper = NULL;
    PSTR pszPatternUpper = NULL;
    BOOLEAN bMatched = FALSE;

    /* 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 */


    for (/* already performed init */;
         PVFS_CSTRING_NON_NULL(pszString) && PVFS_CSTRING_NON_NULL(pszMatch);
         pszString++)
    {
        PVFS_WILDCARD_TYPE eState = 0;
        CHAR cSrc = '\0';
        CHAR cMatch = '\0';
        DWORD dwCount = 0;

        /* Save the current CHAR */

        cSrc = *pszString;
        cMatch = *pszMatch;

        /* Consumes the pattern from pszMatch */

        eState = NextMatchState(&pszMatch, &dwCount);

        switch (eState) {
        case PVFS_WILDCARD_TYPE_NONE:
            if (cSrc != cMatch) {
                ntError = STATUS_NO_MATCH;
                BAIL_ON_NT_STATUS(ntError);
            }
            break;

        case PVFS_WILDCARD_TYPE_SPLAT:
        {
            PSTR pszCursor = NULL;

            /* We are done if this is the last character
               in the pattern */
            if (!PVFS_CSTRING_NON_NULL(pszMatch)) {
                pszString = NULL;
                goto cleanup;
            }

            /* If we don't find a match for the next character
               in the pattern, then fail */
            if ((pszCursor = strchr(pszString, *pszMatch)) == NULL) {
                ntError = STATUS_NO_MATCH;
                BAIL_ON_NT_STATUS(ntError);
            }

            /* Have to consume at least one character here */
            if (pszString == pszCursor) {
                ntError = STATUS_NO_MATCH;
                BAIL_ON_NT_STATUS(ntError);
            }
            /* Set to the previous character so that pszString is
               incremented properly next pass of the loop */
            pszString = pszCursor-1;

            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 */;
            }
            if (*pszString == '\0') {
                /* backup so pszString incrent in outer loop
                   works out */
                pszString--;
            }
            break;
        }

        case PVFS_WILDCARD_TYPE_DOT:
            /* For now deal with the '.' as just another character */
            if (cSrc != cMatch) {
                ntError = STATUS_NO_MATCH;
                BAIL_ON_NT_STATUS(ntError);
            }
            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;
                BAIL_ON_NT_STATUS(ntError);
            }
            pszString = pszCursor;

            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 lefft, it better be on '.' for a match */

            if (pszString && *pszString != '.') {
                ntError = STATUS_NO_MATCH;
                BAIL_ON_NT_STATUS(ntError);
            }

            break;
        }

        }
    }

cleanup:
    /* We matched if pszString is empty AND either pszMatch is empty
       OR only contains wildcard characters */

    if (!PVFS_CSTRING_NON_NULL(pszString) &&
        (!PVFS_CSTRING_NON_NULL(pszMatch) ||
         (!strchr(pszPattern, '?') && !strchr(pszPattern, '*'))))
    {
        bMatched = TRUE;
    }

    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;
}
Example #15
0
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;
}
Example #16
0
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;
}
Example #17
0
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;
}