Menu

#82 FreeRTOS-Plus-FAT-SL wrong FAT entry

v1.0 (example)
closed
None
5
2014-04-23
2014-02-28
Heiko
No

Settings:
Sector size = cluster size = 512 byte
Fat12

Process:
pFile = f_open("name.bin", "w+"); // Create file. In my case cluster 3 (sector 42)
f_write(data, 1, 512, pFile); // Allocate cluster 4 (sector 43) at the end
f_close(pFile);
pFile = f_open("name.bin", "r+");
f_seek(pFile, 512, F_SEEK_SET);
f_write(data, 1, 512, pFile); // cause a wrong fat entry at the next f_open(); f_write();

What happened:
f_seek() set gl_file.relpos to 512 but didn’t change gl_file.pos

fn_write() increment gl_file.pos.sector, copies the data to the local buffer (gl_sector) and calls _f_emptywritebuffer()

_f_emptywritebuffer() writes the data to cluster 5 (that’s the correct cluster). But gl_file.pos.cluster was not incremented so _f_getclustervalue() returns cluster 4 for the next cluster. Because the next cluster is 4 there will be no allocation for the next cluster.

At the next "f_open(); f_seek(); f_write();" _f_emptywritebuffer() writes to cluster 5 (that’s also the correct cluster) and allocates cluster 11. The FAT entries are now cluster 3 -> cluster 4 -> cluster 11 (-> = points to). But Cluster 5 is be missing in the FAT chain.

Discussion

  • Heiko

    Heiko - 2014-03-03

    I fixed the issue by editing the function _f_fseek().

    Code:
    static FatErrorCodeType _f_fseek ( long offset )
    {
    unsigned long cluster;
    unsigned long tmp;
    FatErrorCodeType ret = F_NO_ERROR;
    long remain;

    if ( offset < 0 )
    {
        offset = 0;
    }
    
    if ( ( (unsigned long) offset <= gl_file.filesize )
        && ( (unsigned long) offset >= gl_file.abspos )
            && ( (unsigned long) offset < gl_file.abspos + F_SECTOR_SIZE ) )
    {
        gl_file.relpos = (unsigned short)( (unsigned long)offset - gl_file.abspos );
    }
    else
    {
        if ( gl_file.modified )
        {
            ret = _f_writeglsector( (unsigned long)-1 );
            if ( ret )
            {
                gl_file.mode = F_FILE_CLOSE; /*cant accessed any more*/
                return ret;
            }
        }
    
        if ( gl_file.startcluster )
        {
            gl_file.abspos = 0u;
            gl_file.relpos = 0u;
            gl_file.prevcluster = 0u;
            gl_file.pos.cluster = gl_file.startcluster;
            remain = (long)gl_file.filesize;
    
            tmp = gl_volume.bootrecord.sector_per_cluster;
            tmp *= F_SECTOR_SIZE;   /* set to cluster size */
    
            /*calc cluster*/
            gl_volume.fatsector = (unsigned long)-1;
            while ( (unsigned long)offset >= tmp )
            {
                ret = _f_getclustervalue( gl_file.pos.cluster, &cluster );
                if ( ret )
                {
                    gl_file.mode = F_FILE_CLOSE;
                    return ret;
                }
    
                if ( (long) tmp > remain )
                {
                    break;
                }
    
                if ( (long) tmp == remain )
                {
                    /* cluster boarder so check if the next cluster exists */
                    if ( cluster >= F_CLUSTER_RESERVED )
                    {
                        ret = _f_alloccluster( &cluster );
                        if ( ret )
                        {
                            return ret;
                        }
    
                        ret = _f_setclustervalue( cluster, F_CLUSTER_LAST );
                        if ( ret )
                        {
                            return ret;
                        }
    
                        ret = _f_setclustervalue( gl_file.pos.cluster, cluster );
                        if ( ret )
                        {
                            return ret;
                        }
                    }
                }
    
                remain -= (long)tmp;
                offset -= (long)tmp;
                gl_file.abspos += tmp;
                if ( cluster >= F_CLUSTER_RESERVED )
                {
                    break;
                }
    
                gl_file.prevcluster = gl_file.pos.cluster;
                gl_file.pos.cluster = cluster;
            }
    
            _f_clustertopos( gl_file.pos.cluster, &gl_file.pos );
            if ( remain && offset )
            {
                while ( ( offset > (long) F_SECTOR_SIZE )
                        && ( remain > (long) F_SECTOR_SIZE ) )
                {
                    gl_file.pos.sector++;
                    offset -= (long)F_SECTOR_SIZE;
                    remain -= (long)F_SECTOR_SIZE;
                    gl_file.abspos += F_SECTOR_SIZE;
                }
            }
    
            if ( remain < offset )
            {
                gl_file.relpos = (unsigned short)remain;
                ret = _f_extend( (long)gl_file.filesize + offset - remain );
            }
            else
            {
                gl_file.relpos = (unsigned short)offset;
            }
        }
    }
    
    return ret;
    

    } / _f_fseek /

     
  • Richard Barry

    Richard Barry - 2014-03-04

    Thank you for the information - this is being looked at internally.

    Regards.

     
  • Richard Barry

    Richard Barry - 2014-03-04
    • assigned_to: Real Time Engineers ltd.
     
  • Richard Barry

    Richard Barry - 2014-04-23
    • status: open --> closed
     
  • Richard Barry

    Richard Barry - 2014-04-23

    Fixed in V1.0.1, which is already available in SVN, and will be included in FreeRTOS V8.0.1.

     

Log in to post a comment.

MongoDB Logo MongoDB