示例#1
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;
                    }
                }
            }
        }
    }
示例#2
0
MFS_DIR_ENTRY_PTR MFS_Create_directory_entry
    (
    MFS_DRIVE_STRUCT_PTR    drive_ptr,  /*[IN] the drive on which to operate */
    char_ptr        filename_ptr,       /*[IN] pointer to the file's name */
    char            attribute,          /*[IN] attribute to be assigned to the file */
    uint_32_ptr     dir_cluster_ptr,    /*[IN/OUT] indicates cluster in which the entry was put.*/
    uint_32_ptr     dir_index_ptr,      /*[IN/OUT] index of the location of new file within the directory */
    uint_32_ptr     error_ptr           /*[IN/OUT] error_return_address */
    )
{
    MFS_DIR_ENTRY_PTR     dir_entry_ptr, dir_entry_ptr1;
    MFS_DIR_ENTRY_PTR     temp_entry_ptr;
    TIME_STRUCT           time;
    DATE_STRUCT           clk_time;
    uint_32               dir_index, saved_index, temp_index;
    uint_32               entry_cluster, saved_cluster, temp_cluster;
    uint_32               needed_entries, i;
    int_32                length;
    boolean               found_all = FALSE;
    char                  temp_name[SFILENAME_SIZE+1], short_name[SFILENAME_SIZE+1];  
    uchar                 checksum = 0;
    uint_32               prev_cluster= CLUSTER_INVALID, saved_prev_cluster, temp_prev_cluster; 

    dir_entry_ptr = NULL;
    entry_cluster = *dir_cluster_ptr;
    dir_index = 0;

    /*
    ** Check for duplicate file
    */
    if ( filename_ptr == NULL )
    {
        *error_ptr = MFS_INVALID_PARAMETER;
    }
    else if ( *filename_ptr == '\0' )
    {
        *error_ptr = MFS_FILE_NOT_FOUND;
    }
#if MFSCFG_READ_ONLY_CHECK
    else if (MFS_is_read_only (NULL, drive_ptr))
    {
        *error_ptr = MFS_DISK_IS_WRITE_PROTECTED;
    }
#endif
    else if ( (dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, filename_ptr,
        &entry_cluster, &dir_index, &prev_cluster, MFS_ATTR_ANY, error_ptr)) != NULL )
    {
        *error_ptr = MFS_FILE_EXISTS;
    }
    else
    {
        /*
        ** Search for an empty slot
        */

        dir_index = 0;
        dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); 


        if ( MFS_Dirname_valid(filename_ptr) )
        {
            found_all = TRUE;
        }

        if ( dir_entry_ptr ==  NULL && !*error_ptr )
        {
            found_all = TRUE;
        }

        /* 
        ** Save it now because we might not go into the while loop
        ** If we don't go into while, we lose original values when these 
        ** variables are restored after the while loop
        */
        saved_cluster = entry_cluster;
        saved_index = dir_index;

        while ( !found_all )
        {
            /* Calculate the amount of extra entries needed for LFN's */
            saved_cluster = entry_cluster;
            saved_index = dir_index;

            for ( needed_entries = (strlen(filename_ptr) + 12) / 13;  needed_entries >= 1 && !found_all; needed_entries-- )
            {
                *error_ptr = MFS_Increment_dir_index(drive_ptr, &entry_cluster, &dir_index, NULL);  
                if ( entry_cluster == CLUSTER_EOF && !*error_ptr )
                {
                    /* This means the LFN will span a cluster. */
                    found_all = TRUE;
                    break;
                }
                temp_index = dir_index;
                temp_cluster = entry_cluster;
                temp_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, MFS_ATTR_ANY,error_ptr); 
                if ( *error_ptr )
                {
                    return NULL;
                }
                if ( !temp_entry_ptr )
                {
                    found_all = TRUE;
                    dir_entry_ptr = NULL;
                    break;
                }
                else if ( dir_index == temp_index && temp_cluster == entry_cluster )
                {
                    continue;
                }
                else
                {
                    break;
                }        
            }  

            if ( needed_entries == 0 )
            {
                found_all = TRUE;
            }

            if ( found_all )
            {
                dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &saved_cluster, &saved_index, &saved_prev_cluster, MFS_ATTR_ANY,error_ptr); 
            }
        }  

        entry_cluster = saved_cluster;
        dir_index = saved_index;


        if ( dir_entry_ptr ==  NULL && !*error_ptr )
        {
            /*
            ** Empty spot not found... get a new cluster and use the first entry.
            */
            dir_index = 0;
            if ( entry_cluster == 0 )
            {
                *error_ptr = MFS_ROOT_DIR_FULL;
                return(NULL);
            }
            else
            {
                *error_ptr = MFS_Add_cluster_to_chain(drive_ptr, entry_cluster, &entry_cluster);
                if ( *error_ptr == MFS_NO_ERROR )
                {
                    *error_ptr = MFS_Clear_cluster(drive_ptr, entry_cluster);
                    if ( *error_ptr )
                    {
                        return(NULL);
                    }
                    dir_entry_ptr = (pointer) drive_ptr->DIR_SECTOR_PTR;
                    *error_ptr = MFS_Write_back_fat(drive_ptr);
                    if ( *error_ptr )
                    {
                        return(NULL);
                    }
                }
            }  
        }
    }  

    if ( *error_ptr == MFS_NO_ERROR )
    {
        /* At this point we have one of the following cases 
        **
        ** 1. We have a normal 8.3 filename and an empty slot for it
        ** 2. We have a LFN, and a slot which has enough consecutive free slots
        **    to store the LFN, followed by the actual entry
        */

        /* If the file is a normal 8.3 file */
        if ( MFS_Dirname_valid(filename_ptr) )
        {
            _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY));            
            htodc(dir_entry_ptr->ATTRIBUTE, attribute);
            MFS_Expand_dotfile(filename_ptr, dir_entry_ptr->NAME);

            _time_get(&time);
            _time_to_date(&time, &clk_time);
            NORMALIZE_DATE(&clk_time);
            htods(dir_entry_ptr->TIME, PACK_TIME(clk_time));
            htods(dir_entry_ptr->DATE, PACK_DATE(clk_time));   
            drive_ptr->DIR_SECTOR_DIRTY = TRUE;
        }
        else
        {
            /* Case where the file is a LFN */   
            length = strlen(filename_ptr);

            /* Get the 8.3 name and calculate the checksum */
            temp_index = 0;
            temp_cluster = *dir_cluster_ptr;
            *error_ptr = MFS_lfn_to_sfn(filename_ptr, temp_name);

            if ( !*error_ptr )
            {
                do
                {
                    dir_entry_ptr1 = MFS_Find_directory_entry(drive_ptr, temp_name, &temp_cluster, &temp_index, &temp_prev_cluster, MFS_ATTR_ANY, error_ptr); 
                    if ( !*error_ptr && dir_entry_ptr1 != NULL )
                    {
                        MFS_increment_lfn(temp_name);
                        temp_index = 0;       
                    }
                } while ( !*error_ptr && dir_entry_ptr1 != NULL );
                dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); 

                /*
                ** The memory should be cleared after finding the directory entry.
                */
                _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY));

                /* Setup the final slot */
                ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ID |= MFS_LFN_END;
                drive_ptr->DIR_SECTOR_DIRTY = TRUE;

                MFS_Expand_dotfile(temp_name,short_name);
                checksum = MFS_lfn_checksum(short_name);
            }

            while ( length && !*error_ptr )
            {
                i = length - ((length -1) % 13 + 1);
                *error_ptr = MFS_lfn_name_to_entry(filename_ptr + i, (MFS_LNAME_ENTRY_PTR) dir_entry_ptr);

                /* Set the entry number, the checksum value and the attribute */
                ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ID |= (length + 12) / 13;
                ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ALIAS_CHECKSUM= checksum;
                ((MFS_LNAME_ENTRY_PTR) dir_entry_ptr)->ATTR = MFS_ATTR_LFN;
                drive_ptr->DIR_SECTOR_DIRTY = TRUE;

                length -= (length - i);
                if ( length < 0 )
                {
                    length = 0;
                }

                if ( length && !*error_ptr )
                {

                    dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); 
                    if ( dir_entry_ptr ==  NULL && !*error_ptr )
                    {
                        /* No empty spots... We need to get a new cluster */
                        dir_index = 0; 
                        if ( entry_cluster == 0 )
                        {
                            *error_ptr = MFS_ROOT_DIR_FULL; 
                            return(NULL); 
                        }
                        else
                        {
                            *error_ptr = MFS_Add_cluster_to_chain( drive_ptr, entry_cluster, &entry_cluster); 
                            if ( *error_ptr == MFS_NO_ERROR )
                            {
                                *error_ptr = MFS_Clear_cluster(drive_ptr, entry_cluster); 
                                if ( *error_ptr )
                                {
                                    return(NULL); 
                                }
                                dir_entry_ptr = (pointer) drive_ptr->DIR_SECTOR_PTR; 
                                *error_ptr = MFS_Write_back_fat(drive_ptr); 
                                if ( *error_ptr )
                                {
                                    return(NULL); 
                                }
                            }
                        }   
                    }
                    _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY));
                    drive_ptr->DIR_SECTOR_DIRTY = TRUE;
                }
            }  

            /* LFN is written, so write the actual entry */
            if ( !*error_ptr )
            {
                dir_entry_ptr = MFS_Find_directory_entry(drive_ptr, "", &entry_cluster, &dir_index, &prev_cluster, attribute, error_ptr); 
                if ( dir_entry_ptr == NULL && !*error_ptr )
                {
                    dir_index = 0; 
                    if ( entry_cluster == 0 )
                    {
                        *error_ptr = MFS_ROOT_DIR_FULL; 
                        return(NULL); 
                    }
                    else
                    {
                        *error_ptr = MFS_Add_cluster_to_chain( drive_ptr, entry_cluster, &entry_cluster); 
                        if ( *error_ptr == MFS_NO_ERROR )
                        {
                            *error_ptr =  MFS_Clear_cluster(drive_ptr, entry_cluster); 
                            if ( *error_ptr )
                            {
                                return(NULL); 
                            }
                            dir_entry_ptr = (pointer) drive_ptr->DIR_SECTOR_PTR; 
                            *error_ptr = MFS_Write_back_fat(drive_ptr); 
                            if ( *error_ptr )
                            {
                                return(NULL); 
                            }
                        }
                    }   
                }

                _mem_zero(dir_entry_ptr, sizeof (MFS_DIR_ENTRY));
                htodc(dir_entry_ptr->ATTRIBUTE, attribute);
                MFS_Expand_dotfile(temp_name, dir_entry_ptr->NAME);

                _time_get(&time);
                _time_to_date(&time, &clk_time);
                NORMALIZE_DATE(&clk_time);
                htods(dir_entry_ptr->TIME, PACK_TIME(clk_time));
                htods(dir_entry_ptr->DATE, PACK_DATE(clk_time));   
                drive_ptr->DIR_SECTOR_DIRTY = TRUE;
            }
        }  

        if ( *error_ptr )
        {
            return(NULL);
        }
    }

    *dir_cluster_ptr = entry_cluster;
    *dir_index_ptr = dir_index;
    return(dir_entry_ptr);
}