Exemplo n.º 1
0
_mfs_error MFS_Extend_chain
    (
    MFS_DRIVE_STRUCT_PTR    drive_ptr,      /*[IN] the drive on which to operate */
    uint_32                 cluster_number, /*[IN] number of a cluster within the chain */
    uint_32                 num_clusters,   /*[IN] number of clusters to append to chain */   
    uint_32_ptr             added_cluster   /* [IN] pointer to the place where we should put the # of the first  new cluster. */
    )
{
    uint_32    next_cluster;
    _mfs_error error_code;
    boolean    extended;

#if MFSCFG_READ_ONLY_CHECK
    if (MFS_is_read_only (NULL, drive_ptr))
    {
        return MFS_DISK_IS_WRITE_PROTECTED;
    }
#endif

    extended = FALSE;
    error_code = MFS_NO_ERROR;

    if ( cluster_number < CLUSTER_MIN_GOOD || cluster_number > drive_ptr->LAST_CLUSTER )
    {
        error_code = MFS_INVALID_CLUSTER_NUMBER;
    }
    else if ( num_clusters )
    {
        /*
        ** Find the end of the chain
        */
        next_cluster = cluster_number;
        do
        {
            cluster_number = next_cluster;
            error_code = MFS_get_cluster_from_fat(drive_ptr,next_cluster, &next_cluster);
            if ( error_code != MFS_NO_ERROR )
            {
                return error_code;
            }
            else if ( (next_cluster > drive_ptr->LAST_CLUSTER || next_cluster < CLUSTER_MIN_GOOD) && next_cluster != CLUSTER_EOF )
            {
                return(MFS_LOST_CHAIN);
            }
        } while ( next_cluster != CLUSTER_EOF );

        /*
        ** Find a free cluster
        */
        next_cluster = MFS_Find_unused_cluster_from(drive_ptr, cluster_number+1);

        /*
        ** Check to see if the disk is not full.
        */
        if ( next_cluster == CLUSTER_INVALID )
        {
            return MFS_DISK_FULL;
        }

        /*
        ** Link the free cluster to the chain, at the end.
        */
        *added_cluster = next_cluster;
        error_code = MFS_Put_fat(drive_ptr,cluster_number, next_cluster);
        extended = TRUE;

        while ( --num_clusters && !error_code )
        {
            /*
            ** Find a free cluster
            */
            cluster_number = next_cluster;
            next_cluster = MFS_Find_unused_cluster_from(drive_ptr, cluster_number+1);
            /*
            ** Check to see if the disk is not full.
            */
            if ( next_cluster == CLUSTER_INVALID )
            {
                error_code = MFS_Put_fat(drive_ptr,cluster_number, CLUSTER_EOF);
                return MFS_DISK_FULL;
            }
            else
            {
                /*
                ** Link the free cluster to the chain, at the end.
                */
                error_code = MFS_Put_fat(drive_ptr,cluster_number, next_cluster);
            }  
        }  
        if ( extended && !error_code )
        {
            error_code = MFS_Put_fat(drive_ptr,next_cluster, CLUSTER_EOF);
        }
    }

    return(error_code);
}  
Exemplo n.º 2
0
_mfs_error MFS_Add_cluster_to_chain
    (
    MFS_DRIVE_STRUCT_PTR    drive_ptr,      /*[IN] the drive on which to operate */
    uint_32                 cluster_number, /*[IN] number of a cluster within the chain */
    uint_32_ptr             added_cluster   /*[IN] pointer to the place where we should put the # of the new cluster. */  
    )
{
    uint_32     next_cluster,free_cluster;
    _mfs_error  error_code;

#if MFSCFG_READ_ONLY_CHECK
    if (MFS_is_read_only (NULL, drive_ptr))
    {
        return MFS_DISK_IS_WRITE_PROTECTED;
    }
#endif

    if ( cluster_number < CLUSTER_MIN_GOOD || 
        cluster_number > drive_ptr->LAST_CLUSTER )
    {
        error_code = MFS_INVALID_CLUSTER_NUMBER;
    }
    else
    {
        free_cluster = MFS_Find_unused_cluster_from(drive_ptr, drive_ptr->NEXT_FREE_CLUSTER);

        /*
        ** Check to see if the disk is not full.
        */
        if ( free_cluster == CLUSTER_INVALID )
        {
            error_code = MFS_DISK_FULL;
        }
        else
        {
            /*
            ** Find the end of the chain
            */
            next_cluster = cluster_number;
            do
            {
                cluster_number = next_cluster;
                error_code = MFS_get_cluster_from_fat(drive_ptr,next_cluster, &next_cluster);
                if ( error_code != MFS_NO_ERROR )
                {
                    break;
                }
                else if ( next_cluster > drive_ptr->LAST_CLUSTER && next_cluster != CLUSTER_EOF )
                {
                    error_code = MFS_BAD_DISK_UNIT;
                    break;
                }
            } while ( next_cluster != CLUSTER_EOF );

            /*
            ** Link the free cluster to the chain, at the end.
            */
            if ( error_code == MFS_NO_ERROR )
            {
                error_code = MFS_Put_fat(drive_ptr,cluster_number, free_cluster);
                if ( error_code )
                {
                    return(error_code);
                }
                error_code = MFS_Put_fat(drive_ptr,free_cluster, CLUSTER_EOF);
                if ( error_code )
                {
                    return(error_code);
                }
                *added_cluster = free_cluster;
            }
        }  
    }  

    return(error_code);
}  
Exemplo n.º 3
0
/*FUNCTION*-------------------------------------------------------------------
*
* Function Name    :  MFS_Write_device_sector
* Returned Value   :  error_code
* Comments  :
*     Reads or writes consecutive clusters.
*END*---------------------------------------------------------------------*/
_mfs_error MFS_Write_device_sector
    (
    MFS_DRIVE_STRUCT_PTR    drive_ptr,
    uint_32                 sector_number,  /*[IN] sector number to read/write from/to file system medium */
    char_ptr                buffer_ptr      /*[IN/OUT] address of where data is to be stored/written */
    )
{
    uint_32    new_cluster_number, next_cluster, bad_cluster_number;
    uint_32    i;
    uint_32    retries, attempts;
    uint_32    new_sector_number, no_of_sectors;
    char_ptr   temp_buffer_ptr;
    int_32     num, expect_num, shifter, seek_loc, tmp;
    _mfs_error error;

#if MFSCFG_READ_ONLY_CHECK
    if (MFS_is_read_only (NULL, drive_ptr))
    {
        return MFS_DISK_IS_WRITE_PROTECTED;
    }
#endif

    error = MFS_NO_ERROR;

    MFS_LOG(printf("MFS_Write_device_sector %d\n", sector_number));

    if ( sector_number > drive_ptr->BPB.MEGA_SECTORS )
    {
        return(MFS_SECTOR_NOT_FOUND);
    }

    attempts = 0;
    /* Lock device */
    ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_LOCK, &drive_ptr->DRV_NUM);

    if ( drive_ptr->BLOCK_MODE )
    {
        shifter    = 0;
        seek_loc   = sector_number;
        expect_num = 1;
    }
    else
    {
        shifter    = drive_ptr->SECTOR_POWER;
        seek_loc   = sector_number << shifter;
        expect_num = 1 << shifter;
    }  

    MFS_device_write_internal(drive_ptr, seek_loc, buffer_ptr, &expect_num,  &buffer_ptr, shifter);

    if ( expect_num > 0 )
    {
        error = drive_ptr->DEV_FILE_PTR->ERROR;
#if MFSCFG_MAX_CLUSTER_REMAP_ATTEMPTS
        /*
        ** Check to see if the write failed due to a bad sector. If so, 
        ** rewrite cluster by cluster until we find bad cluster, then move 
        ** it.
        */
        temp_buffer_ptr = buffer_ptr;
        if ( drive_ptr->BLOCK_MODE )
        {
            expect_num = drive_ptr->BPB.SECTORS_PER_CLUSTER;
        }
        else
        {
            expect_num = drive_ptr->CLUSTER_SIZE_BYTES;
        }  
        tmp = expect_num;

        for ( i = 0; i < no_of_clusters; i++ )
        {
            MFS_device_write_internal(drive_ptr, seek_loc, temp_buffer_ptr, &expect_num, &buffer_ptr, shifter);

            if ( expect_num > 0 )
            {
                error_code = drive_ptr->DEV_FILE_PTR->ERROR;
                ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_UNLOCK, &drive_ptr->DRV_NUM);
                bad_cluster_number = cluster_number + i;
                error_code = MFS_get_cluster_from_fat(drive_ptr, bad_cluster_number, &next_cluster);
                if ( error_code != MFS_NO_ERROR )
                {
                    /* 
                    ** This is done so that the unlock at end of function
                    ** works properly
                    */
                    ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_LOCK, &drive_ptr->DRV_NUM);
                    break;
                }

                retries = MFSCFG_MAX_CLUSTER_REMAP_ATTEMPTS;

                while ( (error_code != MFS_NO_ERROR) && retries-- )
                {
                    /*
                    ** Mark old cluster BAD 
                    */
                    error_code = MFS_Put_fat(drive_ptr, bad_cluster_number, CLUSTER_BAD);
                    if ( error_code )
                    {
                        break;
                    }

                    /*
                    ** Find available fat, update old FAT as invalid, 
                    ** update new fat, and write new cluster.
                    */
                    new_cluster_number = MFS_Find_unused_cluster_from(drive_ptr, bad_cluster_number);
                    if ( new_cluster_number ==  CLUSTER_INVALID )
                    {
                        /*
                        ** No more clusters
                        */
                        return MFS_DISK_FULL;
                    }

                    new_sector_number = drive_ptr->DATA_START_SECTOR + ((uint_32)(new_cluster_number - CLUSTER_MIN_GOOD)) * drive_ptr->BPB.SECTORS_PER_CLUSTER;

                    ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_LOCK, &drive_ptr->DRV_NUM);

                    expect_num = tmp;

                    MFS_device_write_internal(drive_ptr, new_sector_number << shifter, temp_buffer_ptr, &expect_num, &buffer_ptr, shifter);

                    if ( expect_num > 0 )
                    {
                        error_code = drive_ptr->DEV_FILE_PTR->ERROR;
                    }

                    ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_UNLOCK, &(drive_ptr->DRV_NUM));
                    bad_cluster_number = new_cluster_number;
                }  

                if ( error_code != MFS_NO_ERROR )
                {
                    return MFS_WRITE_FAULT;
                }

                /*
                ** update chain, 
                */
                error_code = MFS_Put_fat(drive_ptr, new_cluster_number, next_cluster);
                if ( error_code )
                {
                    return(error_code);
                }

                if ( handle->PREVIOUS_CLUSTER )
                {
                    error_code = MFS_Put_fat(drive_ptr,handle->PREVIOUS_CLUSTER, new_cluster_number );
                    if ( error_code )
                    {
                        return(error_code);
                    }
                }
                else
                {
                    clustod(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER, new_cluster_number);
                }  
                handle->PREVIOUS_CLUSTER = new_cluster_number;
                ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_LOCK, &drive_ptr->DRV_NUM);
            }
            else
            {
                handle->PREVIOUS_CLUSTER = cluster_number+i;
            }  
            temp_buffer_ptr += drive_ptr->CLUSTER_SIZE_BYTES;
            sector_number   += drive_ptr->BPB.SECTORS_PER_CLUSTER;
        }  
#endif
    }

    /* Unlock device under MFS */
    ioctl(drive_ptr->DEV_FILE_PTR, IO_IOCTL_DEV_UNLOCK, &drive_ptr->DRV_NUM);

    switch ( error )
    {
        case IO_ERROR_WRITE_PROTECTED:
            error = MFS_DISK_IS_WRITE_PROTECTED;
            break;

        case IO_ERROR_WRITE:
            error = MFS_WRITE_FAULT;
            break;

        case IO_ERROR_WRITE_ACCESS:
            error = MFS_SECTOR_NOT_FOUND;
            break;

        case IO_ERROR_READ:
            error = MFS_READ_FAULT;
            break;

        case IO_ERROR_READ_ACCESS:
            error = MFS_SECTOR_NOT_FOUND;
            break;

        default:
            break;
    }  

    return(error);
}  
Exemplo n.º 4
0
_mfs_error  MFS_Create_subdir
    (
        MFS_DRIVE_STRUCT_PTR drive_ptr,
        
        char                *pathname    /*[IN] pathname of the directory to be created */
    )
{
    MFS_DIR_ENTRY_PTR       dir_entry_ptr;
    uint32_t                 dir_cluster;
    uint32_t                 parent_cluster;
    uint32_t                 free_cluster;
    uint32_t                 dir_index;
    _mfs_error              error_code;
    char                *temp_dirname;
    char                *temp_filename;

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

#if MFSCFG_READ_ONLY_CHECK
    if (MFS_is_read_only (drive_ptr))
    {
        return MFS_DISK_IS_WRITE_PROTECTED;
    }
#endif

    error_code = MFS_alloc_2paths(&temp_dirname,&temp_filename);
    if ( error_code != MFS_NO_ERROR )
    {
        return( error_code );
    }
    error_code = MFS_lock_dos_disk( drive_ptr );
    if ( error_code != MFS_NO_ERROR )
    {
        MFS_free_path(temp_dirname);
        MFS_free_path(temp_filename);
        return error_code;
    }

    MFS_Parse_pathname (temp_dirname, temp_filename, pathname);
    dir_cluster = drive_ptr->CUR_DIR_CLUSTER;
    parent_cluster = MFS_Find_directory (drive_ptr, temp_dirname, dir_cluster);

    dir_cluster = parent_cluster;
    if ( MFS_is_valid_lfn(temp_filename) )
    {
        if ( dir_cluster != CLUSTER_INVALID )
        {
            /*
            ** We'll obtain a cluster for the new directory first. If we
            ** cannot create the directory afterwards, it is easier to re-free
            ** the cluster than to remove the new entry.
            */
            free_cluster = MFS_Find_unused_cluster_from(drive_ptr, drive_ptr->NEXT_FREE_CLUSTER);
            if ( free_cluster != CLUSTER_INVALID )
            {
                error_code = MFS_Clear_cluster(drive_ptr, free_cluster);
                if ( error_code )
                {
                    MFS_unlock(drive_ptr,TRUE);
                    MFS_free_path(temp_dirname);
                    MFS_free_path(temp_filename);
                    return( error_code );
                }
                error_code = MFS_Put_fat(drive_ptr, free_cluster, CLUSTER_EOF);
                dir_entry_ptr = MFS_Create_directory_entry(drive_ptr, temp_filename, MFS_ATTR_DIR_NAME, &dir_cluster, &dir_index, &error_code);
                if ( error_code == MFS_NO_ERROR )
                {
                    clustod(dir_entry_ptr->HFIRST_CLUSTER, dir_entry_ptr->LFIRST_CLUSTER, free_cluster);
                    drive_ptr->DIR_SECTOR_DIRTY = TRUE;

                    /*
                    ** We shall now create the "." and ".." entries.
                    */
                    dir_cluster = free_cluster;
                    dir_entry_ptr = MFS_Create_directory_entry(drive_ptr,".",  MFS_ATTR_DIR_NAME, &dir_cluster, &dir_index, &error_code);
                    if ( error_code == MFS_NO_ERROR )
                    {
                        clustod(dir_entry_ptr->HFIRST_CLUSTER,  dir_entry_ptr->LFIRST_CLUSTER, free_cluster);
                        drive_ptr->DIR_SECTOR_DIRTY = TRUE;
                        dir_entry_ptr = MFS_Create_directory_entry(drive_ptr,"..", MFS_ATTR_DIR_NAME, &dir_cluster, &dir_index, &error_code);

                        if ( error_code == MFS_NO_ERROR )
                        {
                            if ( drive_ptr->FAT_TYPE == MFS_FAT32 )
                            {
                                if ( drive_ptr->BPB32.ROOT_CLUSTER == parent_cluster )
                                {
                                    /* 
                                    ** Even though the FAT32 root sector can be 
                                    ** anywhere, it is identified as 0 when referenced 
                                    ** through a directory entry
                                    */          
                                    parent_cluster = 0;
                                }
                            }
                            clustod(dir_entry_ptr->HFIRST_CLUSTER, dir_entry_ptr->LFIRST_CLUSTER, parent_cluster);
                            drive_ptr->DIR_SECTOR_DIRTY = TRUE;
                        }
                    }
                }
                else
                {
                    MFS_Put_fat(drive_ptr, free_cluster, CLUSTER_UNUSED);
                }  
            }
            else
            {
                error_code = MFS_DISK_FULL;
            }  
        }
        else
        {
            error_code = MFS_PATH_NOT_FOUND;
        }  
    }
    else if ( MFS_lfn_dirname_valid(temp_filename) )
    {
        if ( dir_cluster )
        {
            error_code = MFS_FILE_EXISTS;
        }
        else
        {
            error_code = MFS_CANNOT_CREATE_DIRECTORY;
        }  
    }
    else
    {
        error_code = MFS_INVALID_PARAMETER;
    }  

    MFS_free_path(temp_dirname);
    MFS_free_path(temp_filename);
    MFS_unlock(drive_ptr,TRUE);

    return(error_code);
}  
Exemplo n.º 5
0
uint32_t MFS_Write
    (
        MFS_HANDLE_PTR handle,
        
        MFS_DRIVE_STRUCT_PTR drive_ptr,
      
        uint32_t            num_bytes,      /*[IN] number of bytes to be written */ 

        char                *buffer_address, /*[IN/OUT] bytes are written from this buffer */

        _mfs_error_ptr      error_ptr       /*[IN/OUT] error code is written to this address */
    )
{
    uint32_t                 bytes_written;
    uint32_t                 copy_size;
    uint32_t                 cluster_offset;
    uint32_t                 sector_number, sector_index;
    uint32_t                 sector_offset;
    uint32_t                 whole_sectors;
    uint32_t                 cont_sectors;
    uint32_t                 proc_sectors;
    _mfs_error              error, temp_error;
    uint32_t                 file_size;
    uint32_t                 next_cluster;
    bool                 need_hwread;
    uint32_t                 location;
    uint32_t                 num_zeros;
    uint32_t                 zeros_written;
    uint32_t                 zero_size;

#if MFSCFG_READ_ONLY_CHECK
    if (MFS_is_read_only (drive_ptr))
    {
        MFS_set_error_and_return(error_ptr,MFS_DISK_IS_WRITE_PROTECTED,0);
    }
#endif

    if ( buffer_address == NULL )
    {
        MFS_set_error_and_return(error_ptr,MFS_INVALID_PARAMETER,0);
    }

    if ( num_bytes == 0 )
    {
        MFS_set_error_and_return(error_ptr,MFS_NO_ERROR,0);
    }

    error = MFS_lock_dos_disk( drive_ptr );
    if ( error != MFS_NO_ERROR )
    {
        MFS_set_error_and_return(error_ptr,error,0);
    }

    if ( handle->ACCESS == MFS_ACCESS_READ_ONLY )
    {
        MFS_unlock(drive_ptr,FALSE);
        MFS_set_error_and_return(error_ptr,MFS_ACCESS_DENIED,0);
    }

    /*
    ** Setup the current cluster. If this is the first time writing to the file, a cluster needs to be added.
    */
    if ( handle->CURRENT_CLUSTER == 0 )
    {
        handle->PREVIOUS_CLUSTER = 0;
        handle->CURRENT_CLUSTER = clustoh(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER);
        if ( handle->CURRENT_CLUSTER==0 )
        {
            next_cluster = MFS_Find_unused_cluster_from(drive_ptr,drive_ptr->NEXT_FREE_CLUSTER);
            if ( next_cluster != CLUSTER_INVALID )
            {
                clustod(handle->DIR_ENTRY.HFIRST_CLUSTER, handle->DIR_ENTRY.LFIRST_CLUSTER, next_cluster);
                handle->TOUCHED = 1;

                error = MFS_Put_fat(drive_ptr, next_cluster, CLUSTER_EOF);
                if ( error == MFS_NO_ERROR )
                {
                    handle->CURRENT_CLUSTER = next_cluster;
                }
                else
                {
                    MFS_unlock(drive_ptr,FALSE);
                    MFS_set_error_and_return(error_ptr,error,0);
                }
            }
            else
            {
                MFS_unlock(drive_ptr,FALSE);
                MFS_set_error_and_return(error_ptr,MFS_DISK_FULL,0);
            }
        }
    }
    else if ( handle->CURRENT_CLUSTER == CLUSTER_EOF )
    {
        error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER);
        if ( MFS_NO_ERROR != error )
        {
            MFS_unlock(drive_ptr,FALSE);
            MFS_set_error_and_return(error_ptr,error,0);
        }
    }
    else if ( handle->CURRENT_CLUSTER > drive_ptr->LAST_CLUSTER )
    {
        MFS_unlock(drive_ptr,FALSE);
        MFS_set_error_and_return(error_ptr,MFS_DISK_FULL,0);
    }

    /* Make sure location (local variable) never points behind the end of file */
    file_size = mqx_dtohl(handle->DIR_ENTRY.FILE_SIZE);
    location = (handle->LOCATION > file_size) ? file_size : handle->LOCATION;

    /* Calculate sector number and offsets within cluster and sector */
    cluster_offset = OFFSET_WITHIN_CLUSTER(location);
    sector_index = CLUSTER_OFFSET_TO_SECTOR(cluster_offset);
    sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER) + sector_index;
    sector_offset = OFFSET_WITHIN_SECTOR(location);

    /* Calculate possible gap to fill in by zeros if writing behind the end of file */
    num_zeros = handle->LOCATION - location;

    zeros_written = 0;
    bytes_written = 0;

    /* Write zeros to fill in gap if LOCATION points behind the end of file */
    while (zeros_written < num_zeros)
    {
        /* If offset is non-zero, then reading the data is required */
        error = MFS_Read_data_sector(drive_ptr, handle, sector_number, sector_offset != 0);
        if ( error != MFS_NO_ERROR )
            break;

        /* Zero the buffer  */
        zero_size = min(num_zeros-zeros_written, drive_ptr->BPB.SECTOR_SIZE-sector_offset);
        _mem_zero(&drive_ptr->DATA_SECTOR_PTR[sector_offset], zero_size);
        drive_ptr->DATA_SECTOR_DIRTY = TRUE;

        if ( drive_ptr->WRITE_CACHE_POLICY == MFS_WRITE_THROUGH_CACHE )
        {
            error = MFS_Flush_data_sector_buffer(drive_ptr);
            if ( error != MFS_NO_ERROR )
                break;
        }

        zeros_written += zero_size;
        sector_offset += zero_size;

        /*
        ** Check to see if we need to advance to the next sector, which has
        ** the side effect of increasing the cluster number if required.
        */
        if ( sector_offset >= drive_ptr->BPB.SECTOR_SIZE )
        {
            temp_error = MFS_next_data_sector(drive_ptr, handle, &sector_index, &sector_number);
            if (temp_error == MFS_EOF)
            {
                /* Always allocate new cluster, there is something to be written for sure */
                error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER);
                if ( MFS_NO_ERROR == error )
                {
                    sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER);
                    sector_index = 0;
                }

            }
            else
            {
                error = temp_error;
            }
            sector_offset = 0;
        }
    }

    /* Write partial sector if sector_offset is non-zero */
    if ((sector_offset != 0) && (error == MFS_NO_ERROR))
    {
        /* Offset is non-zero, reading the data is required */
        error = MFS_Read_data_sector(drive_ptr, handle, sector_number, TRUE);

        if (error == MFS_NO_ERROR)
        {
            /* The requested lenght of data may span the sector to it's end  */
            copy_size = min(num_bytes, drive_ptr->BPB.SECTOR_SIZE-sector_offset);

            _mem_copy(buffer_address, &drive_ptr->DATA_SECTOR_PTR[sector_offset], copy_size);
            drive_ptr->DATA_SECTOR_DIRTY = TRUE;

            if (drive_ptr->WRITE_CACHE_POLICY == MFS_WRITE_THROUGH_CACHE)
            {
                error = MFS_Flush_data_sector_buffer(drive_ptr);
            }

            if (error == MFS_NO_ERROR)
            {
                bytes_written = copy_size;

                /*
                ** Check to see if we need to advance to the next sector, which has
                ** the side effect of increasing the cluster number if required.
                */
                if ((sector_offset + bytes_written) >= drive_ptr->BPB.SECTOR_SIZE)
                {
                    temp_error = MFS_next_data_sector(drive_ptr, handle, &sector_index, &sector_number);
                    /* Only an error if we are not done writing and can't extend the chain */
                    if (bytes_written < num_bytes)
                    {
                        if (temp_error == MFS_EOF)
                        {
                            /* Allocate new cluster */
                            error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER);
                            /* Update sector_number and index unconditionally - if there was an error the value is never used anyways. */
                            sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER);
                            sector_index = 0;
                        }
                        else
                        {
                            error = temp_error;
                        }
                    }
                }
            }
        }
    }

    /* Check whether the application buffer is properly aligned */
    if ((((uint32_t)buffer_address+bytes_written) & drive_ptr->ALIGNMENT_MASK) == 0)
    {
        /* Yes, use zero copy approach */
        whole_sectors = (num_bytes - bytes_written) >> drive_ptr->SECTOR_POWER;
        while ((whole_sectors > 0) && (error == MFS_NO_ERROR))
        {
            cont_sectors = drive_ptr->BPB.SECTORS_PER_CLUSTER - sector_index;
            if (cont_sectors > whole_sectors)
                cont_sectors = whole_sectors;

            error = MFS_Write_device_sectors(drive_ptr, sector_number, cont_sectors, MFSCFG_MAX_WRITE_RETRIES, buffer_address+bytes_written, &proc_sectors);

            if (proc_sectors > 0)
            {
                bytes_written += proc_sectors * drive_ptr->BPB.SECTOR_SIZE;
                whole_sectors -= proc_sectors;

                /* Advance to next unprocessed sector */
                sector_index += proc_sectors - 1;
                temp_error = MFS_next_data_sector(drive_ptr, handle, &sector_index, &sector_number);
                /* Go on only if we are not done writing yet */
                if ((error == MFS_NO_ERROR) && (bytes_written < num_bytes))
                {
                    if (temp_error == MFS_EOF)
                    {
                        /* Allocate new cluster */
                        error = MFS_Add_cluster_to_chain(drive_ptr, handle->PREVIOUS_CLUSTER, &handle->CURRENT_CLUSTER);
                        /* Update sector_number and index unconditionally - if there was an error the value is never used anyways. */
                        sector_number = CLUSTER_TO_SECTOR(handle->CURRENT_CLUSTER);
                        sector_index = 0;

                    }
                    else
                    {
                        error = temp_error;
                    }
                }
            }
        }
    }
Exemplo n.º 6
0
/*!
 * \brief Find a free cluster, follow a chain and add it to the chain.
 *
 * \param[in] drive_ptr The drive on which to operate.
 * \param[in] cluster_number Number of a cluster within the chain.
 * \param[in] num_clusters Number of clusters to append to chain.
 * \param[in] added_cluster Pointer to the place where we should put the # of the first  new cluster.
 *
 * \return _mfs_error
 */
_mfs_error MFS_Extend_chain(
    MFS_DRIVE_STRUCT_PTR drive_ptr,
    uint32_t cluster_number,
    uint32_t num_clusters,
    uint32_t *added_cluster)
{
    uint32_t next_cluster;
    uint32_t extended;
    _mfs_error error_code;

    if (cluster_number < CLUSTER_MIN_GOOD || cluster_number > drive_ptr->LAST_CLUSTER)
    {
        return MFS_INVALID_CLUSTER_NUMBER;
    }

    if (num_clusters <= 0)
    {
        return MFS_NO_ERROR;
    }

    /* Find the end of the chain */
    next_cluster = cluster_number;
    do
    {
        cluster_number = next_cluster;
        error_code = MFS_get_cluster_from_fat(drive_ptr, cluster_number, &next_cluster);
        if (error_code != MFS_NO_ERROR)
        {
            return error_code;
        }
        else if ((next_cluster > drive_ptr->LAST_CLUSTER || next_cluster < CLUSTER_MIN_GOOD) && next_cluster != CLUSTER_EOF)
        {
            return MFS_LOST_CHAIN;
        }
    } while (next_cluster != CLUSTER_EOF);

    extended = 0;

    while (num_clusters)
    {
        /* Find a free cluster */
        next_cluster = MFS_Find_unused_cluster_from(drive_ptr, cluster_number + 1);

        /* Check to see if the disk is not full */
        if (next_cluster == CLUSTER_INVALID)
        {
            break; /* Condition handled after the loop */
        }

        /* Link the free cluster to the chain, at the end */
        error_code = MFS_Put_fat(drive_ptr, cluster_number, next_cluster);
        if (error_code != MFS_NO_ERROR)
        {
            return error_code;
        }

        if (extended == 0 && added_cluster != NULL)
        {
            *added_cluster = next_cluster;
        }

        extended++;
        cluster_number = next_cluster;
        num_clusters--;
    }

    /* If the chain was extended, write EOF to it's last link */
    if (extended)
    {
        error_code = MFS_Put_fat(drive_ptr, cluster_number, CLUSTER_EOF);
    }

    if (num_clusters && !error_code)
    {
        error_code = MFS_DISK_FULL;
    }

    return error_code;
}