⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fatfs_supp.c

📁 嵌入式FAT文件系统
💻 C
📖 第 1 页 / 共 5 页
字号:
                else                      type = TENTRY_REGULAR;
            }
            else if (entry >= 0x0FFFFFF8) type = TENTRY_LAST;
            else if (0x0FFFFFF7 == entry) type = TENTRY_BAD;
            else                          type = TENTRY_RESERVED;

            break;

        default:
            CYG_ASSERT(false, "Unknown FAT type");
            type = TENTRY_BAD; // least likely to cause damage
    }
    return type;
}

// -------------------------------------------------------------------------
// set_tentry_type()
// Sets the type of FAT table entry.
 
static void 
set_tentry_type(fatfs_disk_t *disk, cyg_uint32 *entry, cyg_uint32 type)
{
    switch (disk->fat_type)
    {
        case FATFS_FAT12:
            switch (type)
            {
                case TENTRY_FREE:     *entry = 0x0000; return;
                case TENTRY_LAST:     *entry = 0x0FF8; return;
                case TENTRY_RESERVED: *entry = 0x0FF0; return;
                case TENTRY_BAD:      *entry = 0x0FF7; return;      
                default:
                    CYG_ASSERT(false, "Unknown tentry type");
            }
            break;
            
        case FATFS_FAT16:
            switch (type)
            {
                case TENTRY_FREE:     *entry = 0x0000; return;
                case TENTRY_LAST:     *entry = 0xFFF8; return;
                case TENTRY_RESERVED: *entry = 0xFFF0; return;
                case TENTRY_BAD:      *entry = 0xFFF7; return;
                default:
                    CYG_ASSERT(false, "Unknown tentry type");
            }
            break;
            
        case FATFS_FAT32:
            switch (type)
            {
                case TENTRY_FREE:     *entry = 0x00000000; return;
                case TENTRY_LAST:     *entry = 0x0FFFFFF8; return;
                case TENTRY_RESERVED: *entry = 0x0FFFFFF0; return;
                case TENTRY_BAD:      *entry = 0x0FFFFFF7; return;      
                default:
                    CYG_ASSERT(false, "Unknown tentry type");
            }
            break;

        default:
            CYG_ASSERT(false, "Unknown FAT type");
    }
}

// -------------------------------------------------------------------------
// get_tentry_next_cluster()
// Gets the the next file cluster number from FAT table entry.
 
static __inline__ cyg_uint32 
get_tentry_next_cluster(fatfs_disk_t *disk, cyg_uint32 entry)
{
    return entry;
}

// -------------------------------------------------------------------------
// set_tentry_next_cluster()
// Sets the the next cluster number to FAT table entry.
 
static __inline__ void 
set_tentry_next_cluster(fatfs_disk_t *disk, 
                        cyg_uint32   *entry, 
                        cyg_uint32    next_cluster)
{
    *entry = next_cluster;
}

//==========================================================================
// FAT cluster functions 

// -------------------------------------------------------------------------
// erase_cluster()
// Erases cluster (fills with 0x00).

static int
erase_cluster(fatfs_disk_t *disk, cyg_uint32 cluster)
{
    cyg_uint8  data[32];
    cyg_uint32 pos;
    cyg_uint32 len;
    int err, i;
    
    pos = 0;
    len = 32;
    memset((void*)data, 0x00, len);
    
    CYG_TRACE1(TCL, "erasing cluster=%d", cluster);

    for (i = 0; i < (disk->cluster_size >> 5); i++)
    {
        err = disk_cluster_write(disk, (void*)data, &len, cluster, pos);
        if (err != ENOERR)
            return err;

        pos += len;
    }
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// mark_cluster()
// Marks cluster (sets the cluster's FAT table entry to given type). 

static int
mark_cluster(fatfs_disk_t *disk, cyg_uint32 cluster, cyg_uint32 type)
{
    cyg_uint32 tentry;
 
    set_tentry_type(disk, &tentry, type);
    return write_tentry(disk, cluster, &tentry);
}

// -------------------------------------------------------------------------
// link_cluster()
// Links two clusters.

static int
link_cluster(fatfs_disk_t *disk, cyg_uint32 cluster1, cyg_uint32 cluster2)
{
    cyg_uint32 tentry;
    
    set_tentry_next_cluster(disk, &tentry, cluster2);
    return write_tentry(disk, cluster1, &tentry);
}

// -------------------------------------------------------------------------
// find_next_free_cluster()
// Finds first free cluster starting from given cluster.
// If none is available free_cluster is set to 0.
// If CO_MARK_LAST is set in opts the found cluster is marked as LAST.
// If CO_ERASE_NEW is set in opts the found cluster is erased.

static int
find_next_free_cluster(fatfs_disk_t   *disk,
                       cyg_uint32      start_cluster, 
                       cyg_uint32     *free_cluster,
                       cluster_opts_t  opts)
{
    cyg_uint32 c, tentry;
    int        err;

    if (start_cluster < 2) c = 2;
    else                   c = start_cluster + 1;

    *free_cluster = 0;

    CYG_TRACE1(TCL, "starting at cluster=%d", c);
   
    // Search from the starting cluster to the end of FAT and
    // from start of FAT to the starting cluster
    while (c != start_cluster)
    {
        // Check for end of FAT
        if (c >= disk->fat_tbl_nents)
        {
            c = 2;
            if (c >= start_cluster)
                break;
        }

        err = read_tentry(disk, c, &tentry);
        if (err != ENOERR)
            return err;

        if (TENTRY_FREE == get_tentry_type(disk, tentry))
        {
            CYG_TRACE1(TCL, "found free cluster=%d", c);
            
            *free_cluster = c;
            
            if (opts & CO_MARK_LAST)
                err = mark_cluster(disk, c, TENTRY_LAST);
            if ((err == ENOERR) && (opts & CO_ERASE_NEW))
                err = erase_cluster(disk, c);
            
            return err;
        }
        c++;
    }   

    // No free clusters found

    CYG_TRACE0(TCL, "!!! no free clusters found");
 
    return ENOSPC;
}

// -------------------------------------------------------------------------
// find_and_append_cluster()
// Finds a free cluster on disk and appends it to the given cluster. 
// New cluster is marked as LAST. 

static int
find_and_append_cluster(fatfs_disk_t   *disk, 
                        cyg_uint32      cluster, 
                        cyg_uint32     *new_cluster,
                        cluster_opts_t  opts)
{
    cyg_uint32 free_cluster;
    int        err;

    err = find_next_free_cluster(disk, cluster, 
        &free_cluster, opts | CO_MARK_LAST);
    if (err != ENOERR)
        return err;

    err = link_cluster(disk, cluster, free_cluster);
    if (err != ENOERR)
        return err;

    *new_cluster = free_cluster;

    CYG_TRACE2(TCL, "appending new cluster=%d to cluster=%d", 
                    free_cluster, cluster);
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// find_nth_cluster0()
// Finds nth cluster in chain (ie nth cluster of file) searching
// from given position. The result is returned by the same position
// variable. 
 
static int
find_nth_cluster0(fatfs_disk_t     *disk,
                  fatfs_data_pos_t *pos, 
                  cyg_uint32        n)
{
    cyg_uint32 cluster, cluster_snum;
    int        err = ENOERR;
 
    if (pos->cluster_snum == n)
        return ENOERR;

    cluster      = pos->cluster;
    cluster_snum = pos->cluster_snum;
   
    CYG_TRACE4(TCL, "cluster=%d snum=%d n=%d n_to_search=%d",
                    cluster, cluster_snum, n, n-cluster_snum);
   
    // Adjust the number of clusters that should be
    // walked according to the given position
    n -= cluster_snum;

    // Walk the cluster chain for n clusters or until last cluster
    while (n > 0)
    {
        cyg_uint32 tentry;

        err = read_tentry(disk, cluster, &tentry);
        if (err != ENOERR)
            return err;

        switch (get_tentry_type(disk, tentry))
        {
            case TENTRY_REGULAR:
                break;
            case TENTRY_LAST:
                CYG_TRACE1(TCL, "chain end at n=%d", n);
                err = EEOF; // File has less clusters than given n
                            // this err should be caught by the 
                            // calling function 
                goto out;
            default:
                // Inconsistant FAT table state !!!
                CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x n=%d", 
                                tentry, n);
                err = EIO;                 
                goto out;
        }
        cluster = get_tentry_next_cluster(disk, tentry);
        cluster_snum++;
        n--;
    }
    
out:
    pos->cluster      = cluster;
    pos->cluster_snum = cluster_snum;

    CYG_TRACE2(TCL, "nth cluster=%d snum=%d", cluster, cluster_snum);

    return err;
}

// -------------------------------------------------------------------------
// find_nth_cluster()
// Finds nth cluster in chain (ie nth cluster of file) searching 
// from given position. The result is returned by the same position
// variable. If the chain ends one cluster before the given nth cluster 
// and the CO_EXTEND is specified, than the chain is extended by one cluster.
 
static int
find_nth_cluster(fatfs_disk_t     *disk,
                 fatfs_data_pos_t *pos, 
                 cyg_uint32        n,
                 cluster_opts_t    opts)
{
    int err;
   
    // Find nth cluster 
    err = find_nth_cluster0(disk, pos, n);    

    // EEOF meens that the cluster chain ended early
    if ((err != EEOF) || !(opts & CO_EXTEND))
        return err;
    
    // Check if one cluster short
    if (pos->cluster_snum == (n - 1))
    {
        // Extend the chain for one cluster
        cyg_uint32 new_cluster;

        // Append new cluster to the end of chain
        err = find_and_append_cluster(disk, pos->cluster, &new_cluster, opts);
        if (err != ENOERR)
            return err;

        // Update position
        pos->cluster       = new_cluster;
        pos->cluster_snum += 1;
        pos->cluster_pos   = 0;

        CYG_TRACE1(TCL, "appended new cluster=%d", new_cluster);
    }
    
    return err;
}

// -------------------------------------------------------------------------
// get_next_cluster()
// Gets next cluster in chain (ie next cluster of file).
// If CO_EXTEND is specified and the current cluster is last in the 
// chain then the chain is extended by one cluster.

static int
get_next_cluster(fatfs_disk_t     *disk,
                 fatfs_data_pos_t *pos,
                 cluster_opts_t    opts)
{
    int err;

    err = find_nth_cluster(disk, pos, pos->cluster_snum + 1, opts);
    if (err != ENOERR)
        return err;

    // Reset inside cluster position
    pos->cluster_pos = 0;
 
    return ENOERR;
}

// -------------------------------------------------------------------------
// get_position_from_off()
// Gets position from given offset. The search is started from the
// given position and the result is returned by the same variable. 
// If CO_EXTEND is specified the file is extended if one cluster too short.

static int
get_position_from_off(fatfs_disk_t     *disk,
                      cyg_uint32        first_cluster,
                      cyg_uint32        offset,
                      fatfs_data_pos_t *pos,
                      cluster_opts_t    opts)
{
    fatfs_data_pos_t new_pos;
    cyg_uint32       n;
    int              err;

    // Position inside the cluster
    new_pos.cluster_pos = offset & (disk->cluster_size - 1);

    // Cluster seq number to be searched for
    n = offset >> disk->cluster_size_log2;

    if (n < pos->cluster_snum)
    { 
        // Start searching from first cluster
        new_pos.cluster      = first_cluster;
        new_pos.cluster_snum = 0;
    }
    else
    {
        // Start searching from the current position
        new_pos.cluster      = pos->cluster;
        new_pos.cluster_snum = pos->cluster_snum;
    }

    err = find_nth_cluster(disk, &new_pos, n, opts);
    
    // Err could be EEOF wich means that the given 
    // offset if out of given file (cluster chain)

    if (EEOF == err)
        new_pos.cluster_pos = disk->cluster_size; 
    
    *pos = new_pos; 
    
    return err;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -