Example #1
0
NTSTATUS
PvfsSysOpenDir(
    IN PCSTR pszDirname,
    OUT OPTIONAL DIR **ppDir
)
{
    NTSTATUS ntError = STATUS_SUCCESS;
    int unixerr = 0;
    DIR *pDir = NULL;

    if ((pDir = opendir(pszDirname)) == NULL) {
        PVFS_BAIL_ON_UNIX_ERROR(unixerr, ntError);
    }

error:
    if (ntError || !ppDir)
    {
        if (pDir)
        {
            PvfsSysCloseDir(pDir);
        }
    }

    if (ppDir)
    {
        *ppDir = pDir;
    }

    return ntError;
}
Example #2
0
static
BOOLEAN
PvfsSysIsEmptyDir(
    PSTR pszDirname
)
{
    NTSTATUS ntError = STATUS_SUCCESS;
    BOOLEAN isEmptyDir = TRUE;
    DIR *pDir = NULL;
    struct dirent *pDirEntry = NULL;
    struct dirent dirEntry = { 0 };

    ntError = PvfsSysOpenDir(pszDirname, &pDir);
    BAIL_ON_NT_STATUS(ntError);

    for (ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry);
            pDirEntry;
            ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry))
    {
        /* First check the error return */
        BAIL_ON_NT_STATUS(ntError);

        if (!LwRtlCStringIsEqual(pDirEntry->d_name, ".", FALSE) &&
                !LwRtlCStringIsEqual(pDirEntry->d_name, "..", FALSE))
        {
            isEmptyDir = FALSE;
            break;
        }
    }

error:
    if (pDir)
    {
        PvfsSysCloseDir(pDir);
    }

    return NT_SUCCESS(ntError) ? isEmptyDir : FALSE;
}
Example #3
0
static
NTSTATUS
PvfsCreateDirOpenIf(
    PPVFS_IRP_CONTEXT pIrpContext
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    IRP_ARGS_CREATE Args = pIrpContext->pIrp->Args.Create;
    PPVFS_PENDING_CREATE pCreateCtx = NULL;
    PVFS_STAT statPath = { 0 };
    PVFS_STAT statFile = { 0 };
    PPVFS_FILE_NAME directoryName = NULL;
    PPVFS_FILE_NAME resolvedDirName = NULL;
    PPVFS_FILE_NAME relativeFileName = NULL;

    ntError = PvfsAllocateCreateContext(&pCreateCtx, pIrpContext);
    BAIL_ON_NT_STATUS(ntError);

    if (IsSetFlag(
            pCreateCtx->OriginalFileName->NameOptions,
            PVFS_FILE_NAME_OPTION_DEFINED_STREAM_TYPE))
    {
        // Disallow named streams here (shouldn't happen) and "::$DATA"
        ntError = STATUS_NOT_A_DIRECTORY;
        BAIL_ON_NT_STATUS(ntError);
    }

    ntError = PvfsSplitFileNamePath(
                  &directoryName,
                  &relativeFileName,
                  pCreateCtx->OriginalFileName);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsLookupPath2(
                  &resolvedDirName,
                  &statPath,
                  directoryName,
                  IsSetFlag(Args.FileName.IoNameOptions, IO_NAME_OPTION_CASE_SENSITIVE));
    BAIL_ON_NT_STATUS(ntError);

    /* Check for file existence */

    ntError = PvfsLookupFile2(
                  &pCreateCtx->ResolvedFileName,
                  &statFile,
                  directoryName,
                  relativeFileName,
                  IsSetFlag(Args.FileName.IoNameOptions, IO_NAME_OPTION_CASE_SENSITIVE));
    pCreateCtx->bFileExisted = NT_SUCCESS(ntError) ? TRUE : FALSE;

    if (!pCreateCtx->bFileExisted)
    {
        ntError = PvfsAppendFileName(
                      &pCreateCtx->ResolvedFileName,
                      resolvedDirName,
                      relativeFileName);
        BAIL_ON_NT_STATUS(ntError);

        ntError = PvfsAccessCheckFile(
                      pCreateCtx->pCcb->pUserToken,
                      resolvedDirName,
                      FILE_ADD_SUBDIRECTORY,
                      &pCreateCtx->GrantedAccess);
        BAIL_ON_NT_STATUS(ntError);

        pCreateCtx->GrantedAccess = PvfsGetGrantedAccessForNewObject(
                                            Args.DesiredAccess);
    }
    else
    {
        if (!S_ISDIR(statFile.s_mode))
        {
            ntError = STATUS_NOT_A_DIRECTORY;
            BAIL_ON_NT_STATUS(ntError);
        }

        ntError = PvfsAccessCheckFile(
                      pCreateCtx->pCcb->pUserToken,
                      pCreateCtx->ResolvedFileName,
                      Args.DesiredAccess,
                      &pCreateCtx->GrantedAccess);
        BAIL_ON_NT_STATUS(ntError);
    }

    ntError = PvfsCheckDosAttributes(
                  Args,
                  pCreateCtx->bFileExisted ? pCreateCtx->ResolvedFileName : NULL,
                  pCreateCtx->GrantedAccess);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCheckShareMode(
                  pCreateCtx->ResolvedFileName,
                  Args.ShareAccess,
                  pCreateCtx->GrantedAccess,
                  &pCreateCtx->pScb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCreateFileCheckPendingDelete(pCreateCtx->pScb);
    BAIL_ON_NT_STATUS(ntError);

    if (!pCreateCtx->bFileExisted)
    {
        pCreateCtx->SetPropertyFlags = PVFS_SET_PROP_SECURITY|
                                       PVFS_SET_PROP_ATTRIB;
    }

    ntError = PvfsAddCCBToSCB(pCreateCtx->pScb, pCreateCtx->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCreateDirDoSysOpen(pCreateCtx);
    BAIL_ON_NT_STATUS(ntError);

cleanup:
    PvfsFreeCreateContext(OUT_PPVOID(&pCreateCtx));

    if (directoryName)
    {
        PvfsFreeFileName(directoryName);
    }
    if (relativeFileName)
    {
        PvfsFreeFileName(relativeFileName);
    }
    if (resolvedDirName)
    {
        PvfsFreeFileName(resolvedDirName);
    }

    return ntError;

error:
    if (ntError != STATUS_PENDING)
    {
        pIrpContext->pIrp->IoStatusBlock.CreateResult =
            PvfsSetCreateResult(
                Args.CreateDisposition,
                pCreateCtx ? pCreateCtx->bFileExisted : FALSE,
                ntError);
    }

    if (pCreateCtx &&
        pCreateCtx->pCcb &&
        pCreateCtx->pCcb->pDirContext &&
        pCreateCtx->pCcb->pDirContext->pDir)
    {
        PvfsSysCloseDir(pCreateCtx->pCcb->pDirContext->pDir);
    }

    goto cleanup;
}
Example #4
0
static
NTSTATUS
PvfsCreateDirOpen(
    PPVFS_IRP_CONTEXT pIrpContext
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    IRP_ARGS_CREATE Args = pIrpContext->pIrp->Args.Create;
    PPVFS_PENDING_CREATE pCreateCtx = NULL;
    PVFS_STAT Stat = {0};

    ntError = PvfsAllocateCreateContext(&pCreateCtx, pIrpContext);
    BAIL_ON_NT_STATUS(ntError);

    if (IsSetFlag(
            pCreateCtx->OriginalFileName->NameOptions,
            PVFS_FILE_NAME_OPTION_DEFINED_STREAM_TYPE))
    {
        // Disallow named streams here (shouldn't happen) and "::$DATA"
        ntError = STATUS_NOT_A_DIRECTORY;
        BAIL_ON_NT_STATUS(ntError);
    }

    ntError = PvfsLookupPath2(
                  &pCreateCtx->ResolvedFileName,
                  &Stat,
                  pCreateCtx->OriginalFileName,
                  IsSetFlag(Args.FileName.IoNameOptions, IO_NAME_OPTION_CASE_SENSITIVE));
    BAIL_ON_NT_STATUS(ntError);

    if (!S_ISDIR(Stat.s_mode))
    {
        ntError = STATUS_NOT_A_DIRECTORY;
        BAIL_ON_NT_STATUS(ntError);
    }

    ntError = PvfsAccessCheckFile(
                  pCreateCtx->pCcb->pUserToken,
                  pCreateCtx->ResolvedFileName,
                  Args.DesiredAccess,
                  &pCreateCtx->GrantedAccess);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCheckDosAttributes(
                  Args,
                  pCreateCtx->bFileExisted ? pCreateCtx->ResolvedFileName : NULL,
                  pCreateCtx->GrantedAccess);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCheckShareMode(
                  pCreateCtx->ResolvedFileName,
                  Args.ShareAccess,
                  pCreateCtx->GrantedAccess,
                  &pCreateCtx->pScb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCreateFileCheckPendingDelete(pCreateCtx->pScb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCheckQuotaFile(&Args, pCreateCtx->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    pCreateCtx->bFileExisted = TRUE;

    ntError = PvfsAddCCBToSCB(pCreateCtx->pScb, pCreateCtx->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCreateDirDoSysOpen(pCreateCtx);
    BAIL_ON_NT_STATUS(ntError);

cleanup:
    PvfsFreeCreateContext(OUT_PPVOID(&pCreateCtx));

    return ntError;

error:
    if (ntError != STATUS_PENDING)
    {
        pIrpContext->pIrp->IoStatusBlock.CreateResult =
            PvfsSetCreateResult(
                Args.CreateDisposition,
                pCreateCtx ? pCreateCtx->bFileExisted : FALSE,
                ntError);
    }

    if (pCreateCtx &&
        pCreateCtx->pCcb &&
        pCreateCtx->pCcb->pDirContext &&
        pCreateCtx->pCcb->pDirContext->pDir)
    {
        PvfsSysCloseDir(pCreateCtx->pCcb->pDirContext->pDir);
    }

    goto cleanup;
}
Example #5
0
static
NTSTATUS
PvfsCreateDirCreate(
    PPVFS_IRP_CONTEXT pIrpContext
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;
    IRP_ARGS_CREATE Args = pIrpContext->pIrp->Args.Create;
    PPVFS_PENDING_CREATE pCreateCtx = NULL;
    PVFS_STAT statPath = { 0 };
    PPVFS_FILE_NAME directoryName = NULL;
    PPVFS_FILE_NAME relativeFileName = NULL;
    PPVFS_FILE_NAME resolvedDirName = NULL;

    ntError = PvfsAllocateCreateContext(&pCreateCtx, pIrpContext);
    BAIL_ON_NT_STATUS(ntError);

    if (IsSetFlag(
            pCreateCtx->OriginalFileName->NameOptions,
            PVFS_FILE_NAME_OPTION_DEFINED_STREAM_TYPE))
    {
        // Disallow named streams here (shouldn't happen) and "::$DATA"
        ntError = STATUS_NOT_A_DIRECTORY;
        BAIL_ON_NT_STATUS(ntError);
    }

    /* We expect this call to fail with OBJECT_NAME_NOT_FOUND */

    ntError = PvfsLookupPath2(
                  &pCreateCtx->ResolvedFileName,
                  &statPath,
                  pCreateCtx->OriginalFileName,
                  IsSetFlag(Args.FileName.IoNameOptions, IO_NAME_OPTION_CASE_SENSITIVE));
    switch (ntError)
    {
    case STATUS_SUCCESS:
        ntError = STATUS_OBJECT_NAME_COLLISION;
        break;
    case STATUS_OBJECT_NAME_NOT_FOUND:
        ntError = STATUS_SUCCESS;
        break;
    default:
        /* do nothing */
        break;
    }
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsSplitFileNamePath(
                  &directoryName,
                  &relativeFileName,
                  pCreateCtx->OriginalFileName);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsLookupPath2(
                  &resolvedDirName,
                  &statPath,
                  directoryName,
                  IsSetFlag(Args.FileName.IoNameOptions, IO_NAME_OPTION_CASE_SENSITIVE));
    if (ntError == STATUS_OBJECT_NAME_NOT_FOUND)
    {
        ntError = STATUS_OBJECT_PATH_NOT_FOUND;
    }

    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsAppendFileName(
                  &pCreateCtx->ResolvedFileName,
                  resolvedDirName,
                  relativeFileName);
    BAIL_ON_NT_STATUS(ntError);

    /* check parent here */

    ntError = PvfsAccessCheckFile(
                  pCreateCtx->pCcb->pUserToken,
                  resolvedDirName,
                  FILE_ADD_SUBDIRECTORY,
                  &pCreateCtx->GrantedAccess);
    BAIL_ON_NT_STATUS(ntError);

    pCreateCtx->GrantedAccess = PvfsGetGrantedAccessForNewObject(
                                        Args.DesiredAccess);

    ntError = PvfsCheckDosAttributes(
                  Args,
                  NULL,  /* New directory */
                  pCreateCtx->GrantedAccess);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCheckShareMode(
                  pCreateCtx->ResolvedFileName,
                  Args.ShareAccess,
                  pCreateCtx->GrantedAccess,
                  &pCreateCtx->pScb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCreateFileCheckPendingDelete(pCreateCtx->pScb);
    BAIL_ON_NT_STATUS(ntError);

    pCreateCtx->bFileExisted = FALSE;
    pCreateCtx->SetPropertyFlags = PVFS_SET_PROP_SECURITY|PVFS_SET_PROP_ATTRIB;

    ntError = PvfsAddCCBToSCB(pCreateCtx->pScb, pCreateCtx->pCcb);
    BAIL_ON_NT_STATUS(ntError);

    ntError = PvfsCreateDirDoSysOpen(pCreateCtx);
    BAIL_ON_NT_STATUS(ntError);

cleanup:
    PvfsFreeCreateContext(OUT_PPVOID(&pCreateCtx));

    if (directoryName)
    {
        PvfsFreeFileName(directoryName);
    }
    if (relativeFileName)
    {
        PvfsFreeFileName(relativeFileName);
    }
    if (resolvedDirName)
    {
        PvfsFreeFileName(resolvedDirName);
    }

    return ntError;

error:
    if (ntError != STATUS_PENDING)
    {
        pIrpContext->pIrp->IoStatusBlock.CreateResult =
            PvfsSetCreateResult(
                Args.CreateDisposition,
                pCreateCtx ? pCreateCtx->bFileExisted : FALSE,
                ntError);
    }

    if (pCreateCtx &&
        pCreateCtx->pCcb &&
        pCreateCtx->pCcb->pDirContext &&
        pCreateCtx->pCcb->pDirContext->pDir)
    {
        PvfsSysCloseDir(pCreateCtx->pCcb->pDirContext->pDir);
    }

    goto cleanup;
}
Example #6
0
static
NTSTATUS
PvfsSysRemoveDir(
    PSTR pszDirname
)
{
    NTSTATUS ntError = STATUS_SUCCESS;
    DIR *pDir = NULL;
    struct dirent *pDirEntry = NULL;
    struct dirent dirEntry = { 0 };
    PSTR pszPath = NULL;
    PVFS_STAT streamDirStat = { 0 };

    ntError = PvfsSysOpenDir(pszDirname, &pDir);
    BAIL_ON_NT_STATUS(ntError);

    for (ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry);
            pDirEntry;
            ntError = PvfsSysReadDir(pDir, &dirEntry, &pDirEntry))
    {
        /* First check the error return */
        BAIL_ON_NT_STATUS(ntError);

        memset(&streamDirStat, 0, sizeof(PVFS_STAT));
        if (pszPath)
        {
            LwRtlCStringFree(&pszPath);
        }

        ntError = LwRtlCStringAllocatePrintf(
                      &pszPath,
                      "%s/%s",
                      pszDirname,
                      pDirEntry->d_name);
        BAIL_ON_NT_STATUS(ntError);

        ntError = PvfsSysStat(pszPath, &streamDirStat);
        if (ntError == STATUS_SUCCESS)
        {
            if(S_ISDIR(streamDirStat.s_mode))
            {
                if (!LwRtlCStringIsEqual(pDirEntry->d_name, ".", FALSE) &&
                        !LwRtlCStringIsEqual(pDirEntry->d_name, "..", FALSE))
                {
                    ntError = PvfsSysRemoveDir(pszPath);
                    BAIL_ON_NT_STATUS(ntError);
                }
            }
            else
            {
                ntError = PvfsSysRemove(pszPath);
                BAIL_ON_NT_STATUS(ntError);
            }
        }
        else
        {
            // Squash the error is the stream directory did not exist
            ntError = STATUS_SUCCESS;
        }
    }

    ntError = PvfsSysCloseDir(pDir);
    BAIL_ON_NT_STATUS(ntError);
    pDir = NULL;

    ntError = PvfsSysRemove(pszDirname);
    BAIL_ON_NT_STATUS(ntError);

error:
    if (pszPath)
    {
        LwRtlCStringFree(&pszPath);
    }

    if (pDir)
    {
        PvfsSysCloseDir(pDir);
    }

    return ntError;
}
Example #7
0
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;
}
Example #8
0
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;
}