Пример #1
0
_mfs_error MFS_Find_next_slave
    (
    MFS_DRIVE_STRUCT_PTR  drive_ptr,    /*[IN] drive context */
    void     *search_next_ptr           /*[IN] address of search data block indicating the current criteria and the results 
                                        ** of the last search results of this search are placed in this data block */
    )
{
    MFS_SEARCH_DATA_PTR        transfer_ptr;
    MFS_INTERNAL_SEARCH_PTR    internal_search_ptr;
    MFS_DIR_ENTRY_PTR          dir_entry_ptr;
    _mfs_error                 error_code;
    uint32_t                    len;
    bool                    found;
    bool                    match_all;
    bool                    eightdotthree = FALSE;
    char                   *lfn;
    char                       sname[SFILENAME_SIZE+1]; 
    uint32_t                    dotfile = 0;
    MFS_DIR_ENTRY  saved_dir_entry;  

    transfer_ptr = (MFS_SEARCH_DATA_PTR) search_next_ptr;
    error_code = MFS_NO_ERROR;
    found = FALSE;

    if ( transfer_ptr )
    {
        internal_search_ptr = &transfer_ptr->INTERNAL_SEARCH_DATA;

        if ( MFS_alloc_path(&lfn)!= MFS_NO_ERROR )
        {
            return MFS_INSUFFICIENT_MEMORY;
        }

        match_all = MFS_Check_search_string_for_all(internal_search_ptr->SRC_PTR);
        if ( !match_all )
        {
            dotfile = MFS_Is_dot_directory(internal_search_ptr->SRC_PTR);
            if ( dotfile == 0 )
            {
                eightdotthree = MFS_Check_search_string_for_8dot3( internal_search_ptr->SRC_PTR);
            }
        }
        do
        {
            dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, NULL, &internal_search_ptr->CURRENT_CLUSTER, &internal_search_ptr->DIR_ENTRY_INDEX,
                &internal_search_ptr->PREV_CLUSTER, internal_search_ptr->ATTRIBUTE & (~ATTR_EXCLUSIVE), &error_code);

            if ( dir_entry_ptr == NULL && !error_code )
            {
                error_code = MFS_FILE_NOT_FOUND;
                break;
            }

            if ( internal_search_ptr->CURRENT_CLUSTER == CLUSTER_INVALID )
            {
                error_code = MFS_FILE_NOT_FOUND;
                break;
            }

            if ( dir_entry_ptr == NULL )
            {
                break;
            }
            saved_dir_entry=*dir_entry_ptr; 

            /* Make sure the entry is not an LFN entry */
            if ( *dir_entry_ptr->ATTRIBUTE != MFS_ATTR_LFN )
            {
                MFS_Compress_nondotfile (dir_entry_ptr->NAME, sname);

                if ( match_all )
                {
                    found = TRUE;
                }
                else
                {
                    if ( dotfile != 0 )
                    {
                        if ( dotfile == 1 )
                        {
                            found = internal_search_ptr->FULLNAME[0] == dir_entry_ptr->NAME[0];
                        }
                        else if ( dotfile == 2 )
                        {
                            found = (internal_search_ptr->FULLNAME[0] == dir_entry_ptr->NAME[0]) &&
                                    (internal_search_ptr->FULLNAME[1] == dir_entry_ptr->NAME[1]);
                        }
                        else
                        {
                            found = FALSE; /* This shouldn't happen */
                        }
                    }
                    else if ( eightdotthree )
                    {
                        found = MFS_Wildcard_match(internal_search_ptr->FILENAME, dir_entry_ptr->NAME);
                    }
                    else
                    {
                        if ( MFS_get_lfn_dir_cluster(drive_ptr, search_next_ptr, sname, lfn) == MFS_NO_ERROR )
                        {
                            found = MFS_lfn_match(internal_search_ptr->SRC_PTR, lfn, 0);
                        }
                        else
                        {
                            found = MFS_lfn_match(internal_search_ptr->SRC_PTR, sname, 0);
                        }  
                    }  
                }  
            }

            if ( !error_code )
            {
                error_code = MFS_Increment_dir_index(drive_ptr, &internal_search_ptr->CURRENT_CLUSTER,
                    &internal_search_ptr->DIR_ENTRY_INDEX, &internal_search_ptr->PREV_CLUSTER);  
            }

        } while ( (error_code == MFS_NO_ERROR) && (found  == FALSE) );

        if ( error_code == MFS_NO_ERROR )
        {
            transfer_ptr->ATTRIBUTE = mqx_dtohc(saved_dir_entry.ATTRIBUTE);
            transfer_ptr->TIME      = mqx_dtohs(saved_dir_entry.TIME);
            transfer_ptr->DATE      = mqx_dtohs(saved_dir_entry.DATE);
            transfer_ptr->FILE_SIZE = mqx_dtohl(saved_dir_entry.FILE_SIZE);

            /* Transfer the filename */
            len = _strnlen(sname,13);
            if ( sname[len-1] == '.' )
            {
                sname[len-1] = '\0';
            }
            strncpy(transfer_ptr->NAME, sname, 13);
        }

        MFS_free_path((void *)lfn);
    }
    else
    {
        error_code = MFS_INVALID_MEMORY_BLOCK_ADDRESS;
    }  

    return(error_code);
}  
Пример #2
0
void  *MFS_Create_file
    (
        MFS_DRIVE_STRUCT_PTR drive_ptr,
        unsigned char       attr,       /*[IN] attribute for created file*/
        char                *pathname,   /*[IN] directory and filename of the file to be created */
        _mfs_error_ptr      error_ptr   /*[IN/OUT] error code is written to this address */
    )
{
    MFS_HANDLE_PTR          handle;
    MFS_HANDLE_PTR          next_handle;
    MFS_DIR_ENTRY_PTR       dir_entry_ptr;
    TIME_STRUCT             time;
    DATE_STRUCT             clk_time;
    uint32_t                 dir_cluster;
    uint32_t                 dir_index;
    char                    access;
    _mfs_error              error_code, saved_code = 0;

    if ( (pathname == NULL) || (*pathname == '\0') )
    {
        *error_ptr = MFS_INVALID_PARAMETER;
        return( NULL );
    }

#if MFSCFG_READ_ONLY_CHECK
    if (MFS_is_read_only (drive_ptr))
    {
        *error_ptr = MFS_DISK_IS_WRITE_PROTECTED;
        return NULL;
    }
#endif

    error_code = MFS_lock_dos_disk( drive_ptr );
    if ( error_code != MFS_NO_ERROR )
    {
        *error_ptr = error_code;
        return( NULL );
    }

    handle = NULL;

    attr &= (MFS_ATTR_READ_ONLY | MFS_ATTR_HIDDEN_FILE | MFS_ATTR_SYSTEM_FILE | MFS_ATTR_ARCHIVE | MFS_ATTR_VOLUME_NAME);
    attr |= MFS_ATTR_ARCHIVE;
    access = (attr & MFS_ATTR_READ_ONLY) ? MFS_ACCESS_READ_ONLY : MFS_ACCESS_READ_WRITE;
    dir_entry_ptr =  MFS_Create_entry_slave(drive_ptr, attr, pathname, &dir_cluster, &dir_index, &error_code, TRUE);

    if ( (dir_entry_ptr != NULL) && !(attr & MFS_ATTR_VOLUME_NAME) )
    {
        handle = MFS_Get_handle(drive_ptr,dir_entry_ptr);
        if ( handle != NULL )
        {
            handle->DIR_CLUSTER = dir_cluster;
            handle->DIR_INDEX = dir_index;
            handle->ACCESS = access;
            handle->CURRENT_CLUSTER = 0;
            handle->PREVIOUS_CLUSTER = 0;

            /*
            ** If file exists, overwrite and set size to 0
            */
            if ( error_code == MFS_FILE_EXISTS )
            {
                _time_get(&time);
                _time_to_date(&time, &clk_time);
                NORMALIZE_DATE(&clk_time);
                saved_code = MFS_Release_chain(drive_ptr, clustoh(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER));
                if ( saved_code == MFS_NO_ERROR || saved_code == MFS_LOST_CHAIN )
                {
                    clustod(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER, 0);
                    mqx_htodl(handle->DIR_ENTRY.FILE_SIZE, 0L);
                    mqx_htodc(handle->DIR_ENTRY.ATTRIBUTE, attr);
                    mqx_htods(handle->DIR_ENTRY.TIME, PACK_TIME(clk_time));
                    mqx_htods(handle->DIR_ENTRY.DATE, PACK_DATE(clk_time));
                    error_code = MFS_Update_entry(drive_ptr, handle);

                    /*
                    ** If the same file is already open, mark it as 'freshly
                    ** truncated' so reads and writes don't clobber any data.
                    */
                    if ( error_code == MFS_NO_ERROR )
                    {
                        next_handle =  (MFS_HANDLE_PTR) _queue_head(&drive_ptr->HANDLE_LIST);
                        while ( next_handle )
                        {
                            if ( next_handle->DIR_CLUSTER == dir_cluster && next_handle->DIR_INDEX == dir_index )
                            {
                                next_handle->CURRENT_CLUSTER = 0;
                                next_handle->PREVIOUS_CLUSTER = 0;
                            }
                            next_handle =  (MFS_HANDLE_PTR) _queue_next(&drive_ptr->HANDLE_LIST, (QUEUE_ELEMENT_STRUCT_PTR) next_handle);
                        }  
                    }
                }
            }

            /*
            ** No need to update the disk image if we didn't change anything.
            */
            if ( (mqx_dtohc(handle->DIR_ENTRY.ATTRIBUTE) != attr) && (error_code == MFS_NO_ERROR) )
            {
                mqx_htodc(handle->DIR_ENTRY.ATTRIBUTE, attr);
                error_code = MFS_Update_entry(drive_ptr, handle);
            }

        }
        else
        {
            error_code = MFS_INSUFFICIENT_MEMORY;
        }  
    }

    MFS_unlock(drive_ptr,FALSE);

    if ( error_code == MFS_NO_ERROR && saved_code == MFS_LOST_CHAIN )
    {
        *error_ptr = saved_code;
    }
    else
    {
        *error_ptr = error_code; 
    }  

    return((void *)handle);
}  
Пример #3
0
MFS_DIR_ENTRY_PTR MFS_Find_directory_entry
    (
    MFS_DRIVE_STRUCT_PTR  drive_ptr,            /*[IN] drive context */
    char              *file_ptr,             /*[IN] specific name to search for, if NULL then first dir entry */
    uint32_t           *start_cluster_ptr,    /*[IN] start searching in this cluster
                                                **[OUT] set to the cluster number in which search was satisfied */
    uint32_t           *dir_index_ptr,        /*[IN] start searching at this directory entry
                                                **[OUT] if entry is found the index of the next entry is returned */
    uint32_t           *prev_cluster_ptr,     /* [IN] set to the cluster number previous to start_cluster
                                                ** [OUT] set to the cluster number previous to *dir_cluster_ptr */
    unsigned char                 attribute,            /*[IN] search attribute, as per Find_first_file */
    _mfs_error_ptr           error_ptr          /* The pointer carries the error infomation */
    )
{
    MFS_DIR_ENTRY_PTR     dir_entry_ptr = NULL;
    char              *lfn_ptr = NULL;
    bool               found;
    bool               lfn_flag;
    bool               maybe = FALSE;
    bool               found_lfn = FALSE;
    uint32_t               current_cluster, current_index;
    _mfs_error            error_code;
    uint32_t               lfn_len = 0;  
    uint16_t               entries_per_sector;
    uint16_t               k, i;
    char                  lfn_entry[40]; /* LFN entry contains up to 13 UTF16 characters, up to 40 bytes including null term are necessary when encoded using UTF8 */
    char                  fs_file[SFILENAME_SIZE + 1]; 
    uint32_t               prev_cluster = *prev_cluster_ptr; 
    uint32_t               dirname = 0;


    error_code = MFS_NO_ERROR;

    entries_per_sector = drive_ptr->ENTRIES_PER_SECTOR;
    current_cluster = *start_cluster_ptr;
    current_index = *dir_index_ptr;

    found = FALSE;
    lfn_flag = FALSE;

    /* If the name is a LFN, it will be treated differently */
    if ( file_ptr && *file_ptr && !MFS_Dirname_valid(file_ptr) )
    {
        lfn_flag = TRUE;
        lfn_len = _strnlen(file_ptr, PATHNAME_SIZE);
        /* Set pointer just behind the end of the filename */
        lfn_ptr = file_ptr + lfn_len;
        maybe = TRUE;
        found_lfn = FALSE;
        /* We also need special treatement for a directory name */
        if ( attribute == (ATTR_EXCLUSIVE | MFS_ATTR_DIR_NAME) )
        {
            attribute = MFS_ATTR_LFN;
            dirname = 1;
        }
    }
    else if ( file_ptr && *file_ptr )
    {
        MFS_Expand_dotfile(file_ptr, fs_file);
    }
    /*
    ** Search in all clusters within this directory
    */

    do
    {
        /*
        ** Search in all sectors within this cluster
        */
        for ( k = (uint16_t) INDEX_TO_SECTOR(current_index); 
            ((current_cluster == 0) || (k < drive_ptr->BPB.SECTORS_PER_CLUSTER)) && found == FALSE && current_cluster != CLUSTER_EOF;
            k++ )
        {
            dir_entry_ptr = MFS_Read_directory_sector(drive_ptr,current_cluster, k, &error_code);
            if ( dir_entry_ptr == NULL )
            {
                break;
            }

            /*
            ** Search in all entries within this sector
            */
            for ( i = (uint16_t) INDEX_TO_OFFSET(current_index), dir_entry_ptr += i ; i < entries_per_sector && found == FALSE; i++ )
            {
                if ( *dir_entry_ptr->NAME == '\0' ) /* if NEVER USED entry */
                {
                    if ( file_ptr )      /* If not NULL                    */
                    {
                        if ( !*file_ptr )      /* but ""                         */
                        {
                            /* we found it */
                            found = TRUE;
                            break;
                        }
                    }
                    return(NULL);       /* Anyway, stop here-never used entry */
                                        /* if the entry is relevant at all    */

                }
                else if ( (unsigned char) *dir_entry_ptr->NAME == MFS_DEL_FILE )
                {
                    /* If DELETED */ 
                    if ( file_ptr )      /* If not NULL   */
                    {
                        if ( !*file_ptr )      /* but ""  */
                        {
                            found = TRUE;       /* we found it  */
                            break;
                        }
                    }
                }
                else                        /* If REGULAR ENTRY */
                {
                    if ( file_ptr == NULL || *file_ptr )
                    {
                        if ( MFS_Attribute_match(mqx_dtohc(dir_entry_ptr->ATTRIBUTE), 
                            attribute) == TRUE )
                        {
                            if ( !file_ptr )
                            {
                                found = TRUE;
                                break;
                            }
                            else if ( lfn_flag ) /* Searching for a long name */
                            {
                                if ( found_lfn )
                                {
                                    found = TRUE;
                                    break;
                                }
                                if ( !MFS_Attribute_match(mqx_dtohc(dir_entry_ptr->ATTRIBUTE),
                                    MFS_ATTR_LFN) )
                                {
                                    maybe = TRUE; /* Reset maybe */
                                    dir_entry_ptr++;
                                    current_index++;
                                    continue;   /* Not an LFN entry, skip it */ 
                                }
                                if ( !maybe )
                                {
                                    dir_entry_ptr++;
                                    current_index++;
                                    continue;
                                }
                                int chunk_len;
                                chunk_len = MFS_lfn_extract((MFS_LNAME_ENTRY_PTR)dir_entry_ptr, lfn_entry);
                                if(lfn_ptr >= (file_ptr + chunk_len))
                                {
                                    lfn_ptr -= chunk_len;
                                    if ( strncmp(lfn_entry, lfn_ptr, chunk_len) )
                                    {
                                        lfn_ptr = file_ptr + lfn_len; /* reset ptr */
                                        maybe = FALSE;
                                        dir_entry_ptr++;
                                        current_index++;
                                        continue; /* Strings don't match */
                                    }

                                    if ( lfn_ptr == file_ptr )
                                    {
                                        found_lfn = TRUE;
                                        if ( dirname )
                                        {
                                            attribute = ATTR_EXCLUSIVE | MFS_ATTR_DIR_NAME;
                                        }
                                    }
                                }
                                else
                                {
                                    maybe = FALSE;
                                    lfn_ptr = file_ptr + lfn_len; /* reset ptr */
                                }
                            }
                            else /* Searching for a short name */
                            {
                                found = MFS_Wildcard_match(fs_file, dir_entry_ptr->NAME);
                            }  
                        }
                        else
                        {
                            if ( lfn_flag )
                            {
                                attribute = MFS_ATTR_LFN;
                                lfn_ptr = file_ptr + lfn_len; /* reset ptr */
                                maybe = TRUE;
                                found_lfn = FALSE;
                            }
                        }  
                    }
                }  

                if ( found == FALSE )
                {
                    dir_entry_ptr++;
                    current_index++;
                }
            }  
        }  

        if ( found == FALSE )
        {
            error_code = MFS_Increment_dir_index(drive_ptr, &current_cluster, &current_index, &prev_cluster); 
            if ( error_code )
            {
                break;
            }
        }

    } while ( found == FALSE && dir_entry_ptr && current_cluster != CLUSTER_EOF && current_cluster != CLUSTER_INVALID );

    if ( found == FALSE )
    {
        dir_entry_ptr      = NULL;
    }
    else
    {
        *start_cluster_ptr = current_cluster;
        *prev_cluster_ptr = prev_cluster;  
        *dir_index_ptr = current_index;
    }  

    if ( error_ptr )
    {
        *error_ptr = error_code;
    }

    return(dir_entry_ptr);
}  
Пример #4
0
/*FUNCTION*-------------------------------------------------------------------
*
* Function Name    :  MFS_Find_directory
* Returned Value   :  starting_cluster of the specified directory
* Comments  :  Search through the file structure to find the specified
*  directory.  Will search either from the current directory or from the
*  root directory.  Returns the starting cluster number of the specified
*  directory.  If the specified directory cannot be found, then 
*  CLUSTER_INVALID  is returned.
*
*END*---------------------------------------------------------------------*/
uint32_t MFS_Find_directory
    (
    MFS_DRIVE_STRUCT_PTR  drive_ptr,    /*[IN] drive context */
    char              *path_ptr,     /*[IN] specific directory to search for */
    uint32_t               first_cluster /*[IN] start searching in this cluster, used for a relative search*/
    )
{
    MFS_DIR_ENTRY_PTR     dir_entry_ptr;
    char              *directory;
    uint32_t               current_cluster;
    uint32_t               dir_index;
    _mfs_error            error_code;
    bool               flag;
    uint32_t               prev_cluster = CLUSTER_INVALID; 
    unsigned char                 attribute;


    if ( MFS_alloc_path(&directory)!= MFS_NO_ERROR )
    {
        return( CLUSTER_INVALID );
    }

    if ( *path_ptr == '\\' || *path_ptr == '/' )
    {
        current_cluster = ROOT_CLUSTER(drive_ptr);
        path_ptr++;
    }
    else
    {
        current_cluster = first_cluster;
    }  

    while ( path_ptr )
    {
        if ( *path_ptr )
        {
            path_ptr = MFS_Parse_next_filename(path_ptr, directory);

            if ( !MFS_lfn_dirname_valid(directory) )
            {
                current_cluster = CLUSTER_INVALID;
                break;
            }

            flag = FALSE;
            if ( current_cluster == 0 )  flag = TRUE;
            if ( drive_ptr->FAT_TYPE == MFS_FAT32 )
            {
                if ( current_cluster == drive_ptr->BPB32.ROOT_CLUSTER )
                {
                    flag = TRUE;
                }
            }

            if ( flag )
            {
                /*
                ** Special treatment for '.' and '..' in root directory
                */
                dir_index = MFS_Is_dot_directory(directory);
                if ( dir_index == 1 )
                {
                    /* Return the value of the root cluster */
                    MFS_free_path(directory);
                    return ROOT_CLUSTER(drive_ptr);
                }
                else if ( dir_index == 2 )
                {
                    MFS_free_path(directory);
                    return(CLUSTER_INVALID);
                }
            }

            dir_index = 0;

            dir_entry_ptr = MFS_Find_directory_entry( drive_ptr, directory,
                &current_cluster, &dir_index,  &prev_cluster, (~ATTR_EXCLUSIVE),  
                &error_code);

            if ( dir_entry_ptr == NULL )
            {
                current_cluster = CLUSTER_INVALID;
                break;
            }
            else
            {
                attribute = mqx_dtohc(dir_entry_ptr->ATTRIBUTE);

                if ( attribute & MFS_ATTR_DIR_NAME )
                {
                    current_cluster = clustoh(dir_entry_ptr->HFIRST_CLUSTER, dir_entry_ptr->LFIRST_CLUSTER);
                    if ( current_cluster == 0 && drive_ptr->FAT_TYPE == MFS_FAT32 )
                    {
                        current_cluster = drive_ptr->BPB32.ROOT_CLUSTER;
                    }
                }
                else
                {
                    // Found an entry, but it is not a directory
                    MFS_free_path(directory);
                    return(CLUSTER_INVALID);
                }
            }  
        }
        else
        {
            break;
        }  
    }  
    MFS_free_path(directory);

    return(current_cluster);
}  
Пример #5
0
_mfs_error MFS_Remove_subdir
    (
        MFS_DRIVE_STRUCT_PTR drive_ptr,
        
        char                *pathname     /*[IN] pathname of the directory to be removed */
    )
{
    _mfs_error              error_code, saved_error = 0;
    uint32_t                 dir_cluster, parent_cluster, dir_index;
    MFS_DIR_ENTRY_PTR       dir_entry_ptr;
    uint32_t                 prev_cluster= CLUSTER_INVALID; 
    uint32_t                 parent_prev_cluster= CLUSTER_INVALID; 

    if ( (pathname == NULL) || (*pathname == '\0') )
    {
        return MFS_INVALID_PARAMETER;
    }

    error_code = MFS_lock_dos_disk( drive_ptr );
    if ( error_code != MFS_NO_ERROR )
    {
        return error_code;
    }

    dir_entry_ptr = MFS_Find_entry_on_disk (drive_ptr, pathname, &error_code, &parent_cluster, &dir_index,  &parent_prev_cluster);  

    if ( dir_entry_ptr )
    {
        if ( mqx_dtohc(dir_entry_ptr->ATTRIBUTE) & MFS_ATTR_DIR_NAME )
        {
            dir_cluster = clustoh(dir_entry_ptr->HFIRST_CLUSTER, dir_entry_ptr->LFIRST_CLUSTER);
            if ( dir_cluster != drive_ptr->CUR_DIR_CLUSTER )
            {
                dir_index = 2;  /* Skip over '.' and '..' */
                dir_entry_ptr = MFS_Find_directory_entry (drive_ptr, NULL, &dir_cluster, &dir_index, &prev_cluster, MFS_ATTR_ANY, &error_code);  
                if ( dir_entry_ptr == NULL && !error_code )
                {
                    dir_index = 0;
                    dir_entry_ptr = MFS_Find_entry_on_disk (drive_ptr, pathname, &error_code, &parent_cluster, &dir_index, &parent_prev_cluster);
                    if ( dir_entry_ptr )
                    {
                        *dir_entry_ptr->NAME = MFS_DEL_FILE;
                        drive_ptr->DIR_SECTOR_DIRTY = TRUE;
                        error_code = MFS_remove_lfn_entries(drive_ptr, parent_cluster, dir_index, parent_prev_cluster); 
                        if ( !error_code )
                        {
                            saved_error = MFS_Release_chain(drive_ptr, dir_cluster);
                        }
                    }
                }
                else if ( dir_entry_ptr != NULL && !error_code )
                {
                    error_code = MFS_FILE_EXISTS;
                }
            }
            else
            {
                error_code = MFS_ATTEMPT_TO_REMOVE_CURRENT_DIR;
            }  
        }
        else
        {
            error_code = MFS_WRITE_FAULT;
        }  
    }
    else
    {
        error_code = MFS_PATH_NOT_FOUND;
    }  

    MFS_unlock(drive_ptr,TRUE);

    if ( saved_error == MFS_LOST_CHAIN && error_code == MFS_NO_ERROR )
    {
        error_code = saved_error;
    }

    return(error_code);
}  
Пример #6
0
void  *MFS_Open_file
    (
        MFS_DRIVE_STRUCT_PTR drive_ptr,
        char                *pathname,       /*[IN] directory and filename of the file to be opened */
        unsigned char       access,         /*[IN] type of access required: read, write or read/write*/
        uint32_t            *error_ptr   /*[IN/OUT] error code is written to this address */   
    )
{
    MFS_DIR_ENTRY_PTR       dir_entry_ptr;
    MFS_HANDLE_PTR          handle,open_handle;
    uint32_t                 dir_cluster, dir_index;
    _mfs_error              error_code;
    uint32_t                 prev_cluster= CLUSTER_INVALID; 

    if ( (pathname == NULL) || (*pathname == '\0') )
    {
        if ( error_ptr != NULL )
        {
            *error_ptr = MFS_INVALID_PARAMETER;
        }
        return NULL;
    }

    error_code = MFS_lock_dos_disk( drive_ptr );
    if ( error_code != MFS_NO_ERROR )
    {
        if ( error_ptr != NULL )
        {
            *error_ptr = error_code;
        }
        return NULL;
    }

    handle = NULL;

    dir_entry_ptr = MFS_Find_entry_on_disk(drive_ptr, pathname, &error_code, &dir_cluster, &dir_index, &prev_cluster);  

    if ( error_code == MFS_NO_ERROR )
    {

        if ( mqx_dtohc(dir_entry_ptr->ATTRIBUTE) & (MFS_ATTR_DIR_NAME | MFS_ATTR_VOLUME_NAME) )
        {
            error_code = MFS_WRITE_FAULT;
        }
        else if ( (mqx_dtohc(dir_entry_ptr->ATTRIBUTE) & MFS_ATTR_READ_ONLY) && ((access == MFS_ACCESS_WRITE_ONLY) || (access == MFS_ACCESS_READ_WRITE)) )
        {
            error_code = MFS_ACCESS_DENIED;
        }
        else
        {
            // Check to see if the file is already opened
            open_handle = MFS_Find_handle(drive_ptr, dir_cluster, dir_index);
            
            if (open_handle) {
                // If we are opening to write, the file can't already be opened.
                if ((access == MFS_ACCESS_WRITE_ONLY) || (access == MFS_ACCESS_READ_WRITE)) {
                    error_code = MFS_SHARING_VIOLATION;
                }

                // And if we the file is already opened, it can't be opened to write.
                // Note that if it is opened for write, it will be the only instance on the list
                if ((handle->ACCESS == MFS_ACCESS_WRITE_ONLY) || (handle->ACCESS == MFS_ACCESS_READ_WRITE)) {
                    error_code = MFS_SHARING_VIOLATION;
                }
            }
        
            if (error_code == MFS_NO_ERROR) {
                handle = MFS_Get_handle(drive_ptr,dir_entry_ptr);
                if ( handle != NULL )
                {
                    handle->ACCESS = access;
                    handle->CURRENT_CLUSTER = 0;
                    handle->PREVIOUS_CLUSTER = 0;
                    handle->DIR_CLUSTER = dir_cluster;
                    handle->DIR_INDEX = dir_index;
                }
                else
                {
                    error_code = MFS_INSUFFICIENT_MEMORY;
                }  
            }
        }  
    }

    MFS_unlock(drive_ptr,FALSE);

    if ( error_ptr )
    {
        *error_ptr = error_code;
    }

    return((void *) handle);
}  
Пример #7
0
/*!
 * \brief Used to set the MFS drive parameters for a unit.
 *
 * This function assumes that the boot sector of the drive is stored in
 * the drive's sector buffer.  This function is called after MFS is
 * initialized, or after the drive has been formatted.
 *
 * NOTE: It is assumed that the drive is locked by the calling function.
 *
 * \param drive_ptr
 *
 * \return uint32_t Error code.
 */
uint32_t MFS_Mount_drive_internal(
    MFS_DRIVE_STRUCT_PTR drive_ptr)
{
    BIOS_PARAM_STRUCT_DISK_PTR bpb_ptr;
    BIOS_PARAM32_STRUCT_DISK_PTR bpb32_ptr;
    FILESYSTEM_INFO_DISK_PTR fsinfo_ptr;

    uint32_t reserved_sectors;
    uint32_t root_dir_sectors;
    uint32_t data_sectors;
    uint32_t cluster_count;

    uint32_t bpb_sector_size;
    uint32_t bpb_sector_mult;

    int error_code;
    int result = MFS_NO_ERROR;

    uint8_t *boot_sector;

    drive_ptr->DOS_DISK = false;

    error_code = MFS_sector_cache_invalidate(drive_ptr, 0, 0);
    if (error_code != MFS_NO_ERROR)
    {
        return error_code;
    }

    error_code = MFS_sector_map(drive_ptr, BOOT_SECTOR, (void **)&boot_sector, MFS_MAP_MODE_READONLY, 0);
    if (error_code != MFS_NO_ERROR)
    {
        return error_code;
    }

    /*
    ** Extract the drive parameters (BIOS Parameter Block) from the BOOT Record.
    */
    bpb_ptr = (BIOS_PARAM_STRUCT_DISK_PTR)boot_sector;
    bpb32_ptr = (BIOS_PARAM32_STRUCT_DISK_PTR)(boot_sector + sizeof(BIOS_PARAM_STRUCT_DISK));

    /*
    ** Next, check  to see that the BOOT record is that of a DOS disk.  If  not,
    ** the drive will have to be formatted by the upper layer before the drive
    ** can be 'mounted'.
    */
    if ((boot_sector[0] != MFS_DOS30_JMP) && (boot_sector[0] != MFS_DOS30_B))
    {
        result = MFS_NOT_A_DOS_DISK;
    }

    if (result == MFS_NO_ERROR)
    {
        /*
        ** Always use storage device sector size.
        ** If BPB sector size is larger, then recalculate other parameters accordingly.
        ** In any case, BPB sector size has to be multiple of device sector size, the code explicitly checks this.
        */
        bpb_sector_size = mqx_dtohs(bpb_ptr->SECTOR_SIZE);
        if (bpb_sector_size % drive_ptr->SECTOR_SIZE)
        {
            result = MFS_NOT_A_DOS_DISK;
        }
    }

    if (result == MFS_NO_ERROR)
    {
        /* Sector values from BPB are to be multiplied by this factor */
        bpb_sector_mult = bpb_sector_size / drive_ptr->SECTOR_SIZE;

        reserved_sectors = mqx_dtohs(bpb_ptr->RESERVED_SECTORS) * bpb_sector_mult;

        drive_ptr->SECTORS_PER_CLUSTER = mqx_dtohc(bpb_ptr->SECTORS_PER_CLUSTER) * bpb_sector_mult;
        drive_ptr->CLUSTER_POWER_SECTORS = ilog2(drive_ptr->SECTORS_PER_CLUSTER);
        drive_ptr->CLUSTER_POWER_BYTES = drive_ptr->SECTOR_POWER + drive_ptr->CLUSTER_POWER_SECTORS;
        drive_ptr->CLUSTER_SIZE_BYTES = drive_ptr->SECTOR_SIZE * drive_ptr->SECTORS_PER_CLUSTER;

        drive_ptr->NUMBER_OF_FAT = mqx_dtohc(bpb_ptr->NUMBER_OF_FAT);
        drive_ptr->ROOT_ENTRIES = mqx_dtohs(bpb_ptr->ROOT_ENTRIES);

        drive_ptr->SECTORS_PER_FAT = mqx_dtohs(bpb_ptr->SECTORS_PER_FAT);
        if (drive_ptr->SECTORS_PER_FAT == 0)
        {
            drive_ptr->SECTORS_PER_FAT = mqx_dtohl(bpb32_ptr->FAT_SIZE);
        }
        drive_ptr->SECTORS_PER_FAT *= bpb_sector_mult;

        drive_ptr->MEGA_SECTORS = mqx_dtohs(bpb_ptr->NUMBER_SECTORS);
        if (drive_ptr->MEGA_SECTORS == 0)
        {
            drive_ptr->MEGA_SECTORS = mqx_dtohl(bpb_ptr->MEGA_SECTORS);
        }
        drive_ptr->MEGA_SECTORS *= bpb_sector_mult;

        /* Determine FAT type by calculating the count of clusters on disk */
        drive_ptr->ENTRIES_PER_SECTOR = drive_ptr->SECTOR_SIZE / sizeof(DIR_ENTRY_DISK);
        root_dir_sectors = drive_ptr->ROOT_ENTRIES / drive_ptr->ENTRIES_PER_SECTOR;

        data_sectors = drive_ptr->MEGA_SECTORS - reserved_sectors - root_dir_sectors - (drive_ptr->NUMBER_OF_FAT * drive_ptr->SECTORS_PER_FAT);
        cluster_count = data_sectors / drive_ptr->SECTORS_PER_CLUSTER;

        /* Now we have cluster count, so we can determine FAT type */
        if (cluster_count < 4085)
        {
            drive_ptr->FAT_TYPE = MFS_FAT12;
        }
        else if (cluster_count < 65525)
        {
            drive_ptr->FAT_TYPE = MFS_FAT16;
        }
        else
        {
            drive_ptr->FAT_TYPE = MFS_FAT32;
        }

        drive_ptr->CLUSTER_SIZE_BYTES = drive_ptr->SECTOR_SIZE * drive_ptr->SECTORS_PER_CLUSTER;
        drive_ptr->CLUSTER_POWER_BYTES = drive_ptr->SECTOR_POWER + drive_ptr->CLUSTER_POWER_SECTORS;

        drive_ptr->FREE_COUNT = FSI_UNKNOWN; /* This is the unknown value */
        drive_ptr->NEXT_FREE_CLUSTER = FSI_UNKNOWN; /* MFS will calculate it later */

        drive_ptr->FAT_START_SECTOR = reserved_sectors;
        drive_ptr->DATA_START_SECTOR = drive_ptr->FAT_START_SECTOR + (drive_ptr->SECTORS_PER_FAT * drive_ptr->NUMBER_OF_FAT) + root_dir_sectors;

        if (drive_ptr->FAT_TYPE != MFS_FAT32)
        {
            /* FAT12 or FAT16 */
            drive_ptr->ROOT_START_SECTOR = drive_ptr->FAT_START_SECTOR + (drive_ptr->SECTORS_PER_FAT * drive_ptr->NUMBER_OF_FAT);
            drive_ptr->ROOT_CLUSTER = 0;
            MFS_chain_forge(drive_ptr, &drive_ptr->ROOT_CHAIN, drive_ptr->ROOT_START_SECTOR, root_dir_sectors);
        }
        else if (mqx_dtohs(bpb32_ptr->FS_VER) > MFS_FAT32_VER)
        {
            /* Unsupported FAT32 level */
            result = MFS_ERROR_UNKNOWN_FS_VERSION;
        }
        else
        {
            /* Supported FAT32 */
            drive_ptr->ROOT_CLUSTER = mqx_dtohl(bpb32_ptr->ROOT_CLUSTER);
            drive_ptr->ROOT_START_SECTOR = 0;
            MFS_chain_init(drive_ptr, &drive_ptr->ROOT_CHAIN, drive_ptr->ROOT_CLUSTER);

            drive_ptr->FS_INFO = mqx_dtohs(bpb32_ptr->FS_INFO);
        }
    }

    error_code = MFS_sector_unmap(drive_ptr, BOOT_SECTOR, 0);
    if (result == MFS_NO_ERROR)
    {
        result = error_code;
    }

    if (result != MFS_NO_ERROR)
    {
        return result;
    }

    if (drive_ptr->FAT_TYPE == MFS_FAT32)
    {

        /*
        ** Reset the FSInfo->Free_Count and the FSInfo->Next_Free to
        ** unknown (0xFFFFFFFF). MFS uses it's own internal version of these
        ** fields. If Windows uses the same disk, it will recalculate the
        ** correct fields the first time it mounts the drive.
        */

        error_code = MFS_sector_map(drive_ptr, drive_ptr->FS_INFO, (void **)&fsinfo_ptr, MFS_is_read_only(drive_ptr) ? MFS_MAP_MODE_READONLY : MFS_MAP_MODE_MODIFY, 0);
        if (error_code == MFS_NO_ERROR)
        {

            if ((mqx_dtohl(fsinfo_ptr->LEAD_SIG) == FSI_LEADSIG) && (mqx_dtohl(fsinfo_ptr->STRUCT_SIG) == FSI_STRUCTSIG) &&
                (mqx_dtohl(fsinfo_ptr->TRAIL_SIG) == FSI_TRAILSIG))
            {
                drive_ptr->FREE_COUNT = mqx_dtohl(fsinfo_ptr->FREE_COUNT);
                drive_ptr->NEXT_FREE_CLUSTER = mqx_dtohl(fsinfo_ptr->NEXT_FREE);
            }

            if (!MFS_is_read_only(drive_ptr))
            {
                mqx_htodl(fsinfo_ptr->LEAD_SIG, FSI_LEADSIG);
                mqx_htodl(fsinfo_ptr->STRUCT_SIG, FSI_STRUCTSIG);
                mqx_htodl(fsinfo_ptr->FREE_COUNT, FSI_UNKNOWN); /* compute it */
                mqx_htodl(fsinfo_ptr->NEXT_FREE, FSI_UNKNOWN); /* compute it */
                mqx_htodl(fsinfo_ptr->TRAIL_SIG, FSI_TRAILSIG);
            }

            error_code = MFS_sector_unmap(drive_ptr, drive_ptr->FS_INFO, !MFS_is_read_only(drive_ptr));
        }
        if (result == MFS_NO_ERROR)
        {
            result = error_code;
        }
    }

    drive_ptr->LAST_CLUSTER = (drive_ptr->MEGA_SECTORS - drive_ptr->DATA_START_SECTOR) / drive_ptr->SECTORS_PER_CLUSTER + 1;

    drive_ptr->CURRENT_DIR[0] = '\\'; /* Root dir */
    drive_ptr->CURRENT_DIR[1] = '\0';
    drive_ptr->CUR_DIR_CLUSTER = drive_ptr->ROOT_CLUSTER;
    drive_ptr->CUR_DIR_CHAIN_PTR = &drive_ptr->ROOT_CHAIN;

    if (result == MFS_NO_ERROR)
    {
        drive_ptr->DOS_DISK = true;
    }

    return result;
}