Пример #1
0
/* msdos_get_token --
 *     Routine to get a token (name or separator) from the path.
 *
 * PARAMETERS:
 *     path      - path to get token from
 *     ret_token - returned token
 *     token_len - length of returned token
 *
 * RETURNS:
 *     token type, token and token length
 *
 */
msdos_token_types_t
msdos_get_token(const char *path, char *ret_token, int *token_len)
{
    int                 rc = RC_OK;
    register int        i = 0;
    msdos_token_types_t type = MSDOS_NAME;
    char                token[MSDOS_NAME_MAX_WITH_DOT+1];
    register char       c;

    /*
     *  Copy a name into token.  (Remember NULL is a token.)
     */
    c = path[i];
    while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) )
    {
        token[i] = c;
        if ( i == MSDOS_NAME_MAX_WITH_DOT )
            return MSDOS_INVALID_TOKEN;
        if ( !msdos_is_valid_name_char(c) )
            return MSDOS_INVALID_TOKEN;
        c = path [++i];
    }

    /*
     *  Copy a seperator into token.
     */
    if ( i == 0 )
    {
        token[i] = c;
        if ( token[i] != '\0' )
        {
            i++;
            type = MSDOS_CURRENT_DIR;
        }
        else
            type = MSDOS_NO_MORE_PATH;
    }
    else if (token[ i-1 ] != '\0')
        token[i] = '\0';

    /*
     *  Set token_len to the number of characters copied.
     */
    *token_len = i;

    /*
     *  If we copied something that was not a seperator see if
     *  it was a special name.
     */
    if ( type == MSDOS_NAME )
    {
        if ( strcmp( token, "..") == 0 )
        {
            strcpy(ret_token, MSDOS_DOTDOT_NAME);
            type = MSDOS_UP_DIR;
            return type;
        }

        if ( strcmp( token, "." ) == 0 )
        {
            strcpy(ret_token, MSDOS_DOT_NAME);
            type = MSDOS_CURRENT_DIR;
            return type;
        }

        rc = msdos_filename_unix2dos(token, *token_len, ret_token);
        if ( rc != RC_OK )
            return MSDOS_INVALID_TOKEN;
    }
    ret_token[MSDOS_NAME_MAX] = '\0';
    return type;
}
/* msdos_eval4make --
 *     The following routine evaluate path for a new node to be created.
 *     'pathloc' is returned with a pointer to the parent of the new node.
 *     'name' is returned with a pointer to the first character in the
 *     new node name.  The parent node is verified to be a directory.
 *
 * PARAMETERS:
 *     path    - path for evaluation
 *     pathloc - IN/OUT (start point for evaluation/parent directory for
 *               creation)
 *     name    - new node name
 *
 * RETURNS:
 *     RC_OK, filled pathloc for parent directory and name of new node on
 *     success, or -1 if error occured (errno set appropriately)
 */
int
msdos_eval4make(
    const char                         *path,
    rtems_filesystem_location_info_t   *pathloc,
    const char                        **name
    )
{
    int                               rc = RC_OK;
    rtems_status_code                 sc = RTEMS_SUCCESSFUL;
    msdos_fs_info_t                  *fs_info = pathloc->mt_entry->fs_info;
    fat_file_fd_t                    *fat_fd = NULL;
    rtems_filesystem_location_info_t  newloc;
    msdos_token_types_t               type;
    int                               i = 0;
    int                               token_len;
    const char                       *token;
    bool                              done = false;

    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
    if (sc != RTEMS_SUCCESSFUL)
        rtems_set_errno_and_return_minus_one(EIO);

    if (!pathloc->node_access)
    {
        errno = ENOENT;
        rc = -1;
        goto err;
    }

    fat_fd = pathloc->node_access;

    rc = fat_file_reopen(fat_fd);
    if (rc != RC_OK)
        goto err;

    while (!done)
    {
        type = msdos_get_token(&path[i], strlen(&path[i]), &token, &token_len);
        i += token_len;
        fat_fd = pathloc->node_access;

        switch (type)
        {
            case MSDOS_UP_DIR:
                /*
                 *  Only a directory can be decended into.
                 */
                if (fat_fd->fat_file_type != FAT_DIRECTORY)
                {
                    errno = ENOTDIR;
                    rc = -1;
                    goto error;
                }

                /*
                 *  Am I at the root of this mounted filesystem?
                 */
                if (pathloc->node_access ==
                    pathloc->mt_entry->mt_fs_root.node_access)
                {
                    /*
                     *  Am I at the root of all filesystems?
                     *  XXX: MSDOS is not supposed to be base fs.
                     */
                    if (pathloc->node_access ==
                        rtems_filesystem_root.node_access)
                    {
                        break;       /* Throw out the .. in this case */
                    }
                    else
                    {
                        newloc = pathloc->mt_entry->mt_point_node;
                        *pathloc = newloc;

                        rc = fat_file_close(pathloc->mt_entry, fat_fd);
                        if (rc != RC_OK)
                            goto err;

                        rtems_semaphore_release(fs_info->vol_sema);
                        return (*pathloc->ops->evalformake_h)(&path[i-token_len],
                                                              pathloc, name);
                    }
                }
                else
                {
                    rc = msdos_find_name(pathloc, token, token_len);
                    if (rc != RC_OK)
                    {
                        if (rc == MSDOS_NAME_NOT_FOUND_ERR)
                        {
                            errno = ENOENT;
                            rc = -1;
                        }
                        goto error;
                    }
                }
                break;

            case MSDOS_NAME:
                /*
                 *  Only a directory can be decended into.
                 */
                if (fat_fd->fat_file_type != FAT_DIRECTORY)
                {
                    errno = ENOTDIR;
                    rc = -1;
                    goto error;
                }

                /*
                 * Otherwise find the token name in the present location and
                 * set the node access to the point we have found.
                 */
                rc = msdos_find_name(pathloc, token, token_len);
                if (rc)
                {
                    if (rc != MSDOS_NAME_NOT_FOUND_ERR)
                    {
                        errno = ENOENT;
                        rc = -1;
                        goto error;
                    }
                    else
                        done = true;
                }
                break;

            case MSDOS_NO_MORE_PATH:
                errno = EEXIST;
                rc = -1;
                goto error;
                break;

            case MSDOS_CURRENT_DIR:
                break;

            case MSDOS_INVALID_TOKEN:
                errno = ENAMETOOLONG;
                rc = -1;
                goto error;
                break;

        }
    }

    *name = &path[i - token_len];

    /*
     * We have evaluated the path as far as we can.
     * Verify there is not any invalid stuff at the end of the name.
     */
    for( ; path[i] != '\0'; i++)
    {
        if (!msdos_is_separator(path[i]))
        {
            errno = ENOENT;
            rc = -1;
            goto error;
        }
    }

    fat_fd = pathloc->node_access;

    if (fat_fd->fat_file_type != FAT_DIRECTORY)
    {
        errno = ENOTDIR;
        rc = -1;
        goto error;
    }

    msdos_set_handlers(pathloc);

    rtems_semaphore_release(fs_info->vol_sema);
    return RC_OK;

error:
    fat_file_close(pathloc->mt_entry, fat_fd);

err:
    rtems_semaphore_release(fs_info->vol_sema);
    return rc;
}