Exemple #1
0
NTSTATUS
PvfsGetFileAttributes(
    IN PPVFS_CCB pCcb,
    OUT PFILE_ATTRIBUTES pAttributes
    )
{
    NTSTATUS ntError = STATUS_UNSUCCESSFUL;

    *pAttributes = 0;

#ifdef HAVE_EA_SUPPORT
    ntError = PvfsGetFileAttributesXattr(pCcb, pAttributes);
#endif

    /* Fallback to generating a default attribute set */

    if (!NT_SUCCESS(ntError))
    {
        PSTR pszRelativeFilename = NULL;

        ntError = PvfsFileBasename(&pszRelativeFilename, pCcb->pszFilename);
        BAIL_ON_NT_STATUS(ntError);

        *pAttributes |= FILE_ATTRIBUTE_ARCHIVE;

        /* Hide 'dot' files (except "." and "..") */

        if (!RtlCStringIsEqual(pszRelativeFilename, ".", FALSE) &&
            !RtlCStringIsEqual(pszRelativeFilename, "..", FALSE))
        {
            if (*pszRelativeFilename == '.') {
                *pAttributes |= FILE_ATTRIBUTE_HIDDEN;
            }
        }

        RTL_FREE(&pszRelativeFilename);
    }

    /* Some attributes are properties on the file and not
       not settable.  Make sure to clear and then reset if
       necessary */

    *pAttributes &= ~(FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_DIRECTORY);
    if (pCcb->CreateOptions & FILE_DIRECTORY_FILE)
    {
        *pAttributes |= FILE_ATTRIBUTE_DIRECTORY;
    }

    /* FILE_ATTRIBUTE_NORMAL is only valid when the file
       has no other attributes set (according to SetFileAttribues()
       in the MS SDK) */

    if (*pAttributes == 0)
    {
        *pAttributes = FILE_ATTRIBUTE_NORMAL;
    }

    /* This will always succeed somehow */

    ntError = STATUS_SUCCESS;

cleanup:
    return ntError;

error:
    goto cleanup;
}
Exemple #2
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;
}
Exemple #3
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;
}
Exemple #4
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;
}
Exemple #5
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;
}