summaryrefslogblamecommitdiffstats
path: root/cpukit/libfs/src/dosfs/msdos_eval.c
blob: 0bba0c0a5ef1e1522ec33883a6145c4b975bc34f (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                           
                                         
























                               
                                                                           







                             
           

                                                         
                                                      





















                                                                       
  
   
   


                                                
                                              















                                                                           
 




                              
     
 
                                  



                                 

                                                                         


                                                          



                                      









                                                           
                 



                                                                

                                                              




                                                                 


                                                          
                                                                        

                        






                                                                       
 



                                                                              

                    







                                                           


                                   











                                                           
                 

                  
                                                                             








                                                                  


                               


                                    
                                   






                                     
 








                                                                             
                                                                   




                                                                               
 
                                
 







                                               
              









                                                                          
                                                                        



                              
                                                                         

                                                                
   
                

                                                
                                            
     















                                                                           
 




                              
     
 
                                  




                                 
                 


                                                      
                                      
 
                     









                                                           
                 



                                                                

                                                              




                                                                 


                                                          
                                                                        

                        








                                                                       
                                                                           

                                                                             

                    







                                                           


                                   











                                                           
                 

                  
                                                                             












                                                                  
                 






                                    
 

















                                                                    
                                





                                         
         








                                               

     
                                
 







                                               
              
 
/*
 *  MSDOS evaluation routines
 *
 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 *
 *  @(#) $Id$
 */

#if HAVE_CONFIG_H
#include "config.h"
#endif

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <assert.h>

#include <rtems/libio_.h>

#include "fat.h"
#include "fat_fat_operations.h"
#include "fat_file.h"

#include "msdos.h"

/* msdos_set_handlers --
 *     Set handlers for the node with specified type(i.e. handlers for file
 *     or directory).
 *
 * PARAMETERS:
 *     loc - node description
 *
 * RETURNS:
 *     None
 */
static void
msdos_set_handlers(rtems_filesystem_location_info_t *loc)
{
    msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
    fat_file_fd_t   *fat_fd = loc->node_access;

    if (fat_fd->fat_file_type == FAT_DIRECTORY)
        loc->handlers = fs_info->directory_handlers;
    else
        loc->handlers = fs_info->file_handlers;
}

/* msdos_eval_path --
 *
 *     The following routine evaluate path for a node that wishes to be
 *     accessed.  Structure 'pathloc' is returned with a pointer to the
 *     node to be accessed.
 *
 * PARAMETERS:
 *     pathname - path for evaluation
 *     flags    - flags
 *     pathloc  - node description (IN/OUT)
 *
 * RETURNS:
 *     RC_OK and filled pathloc on success, or -1 if error occured
 *     (errno set appropriately)
 *
 */
int
msdos_eval_path(
    const char                        *pathname,
    int                                flags,
    rtems_filesystem_location_info_t  *pathloc
    )
{
    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;
    int                               i = 0;
    int                               len = 0;
    msdos_token_types_t               type = MSDOS_CURRENT_DIR;
    char                              token[MSDOS_NAME_MAX + 1];

    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
    if (sc != RTEMS_SUCCESSFUL)
        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 ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN))
    {
        type = msdos_get_token(&pathname[i], token, &len);
        i += 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->evalpath_h)(&(pathname[i-len]),
                                                           flags, pathloc);
                    }
                }
                else
                {
                    rc = msdos_find_name(pathloc, token);
                    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);
                if (rc != RC_OK)
                {
                    if (rc == MSDOS_NAME_NOT_FOUND_ERR)
                    {
                        errno = ENOENT;
                        rc = -1;
                    }
                    goto error;
                }
                break;

            case MSDOS_NO_MORE_PATH:
            case MSDOS_CURRENT_DIR:
                break;

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

        }
    }

    /*
     *  Always return the root node.
     *
     *  If we are at a node that is a mount point. Set loc to the
     *  new fs root node and let let the mounted filesystem set the handlers.
     *
     *  NOTE: The behavior of stat() on a mount point appears to be
     *        questionable.
     *  NOTE: MSDOS filesystem currently doesn't support mount functionality ->
     *        action not implemented
     */
    fat_fd = pathloc->node_access;

    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;
}

/* 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                               len;
    char                              token[ MSDOS_NAME_MAX + 1 ];
    rtems_boolean                     done = 0;

    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
    if (sc != RTEMS_SUCCESSFUL)
        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], token, &len);
        i += 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-len],
                                                              pathloc, name);
                    }
                }
                else
                {
                    rc = msdos_find_name(pathloc, token);
                    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);
                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 - 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;
}