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

📄 fatfs_supp.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
    cyg_uint32 c, tentry;
    int err;

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

    *free_cluster = 0;

    CYG_TRACE1(TCL, "c=%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)
    {
        // End of FAT check
        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, "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 out of space
    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;

    CYG_TRACE1(TCL, "cluster=%d", cluster);
    
    err = find_next_free_cluster(disk, cluster, 
            &free_cluster, opts | CO_MARK_LAST);
    if (err != ENOERR)
        return err;

    CYG_TRACE1(TCL, "free_cluster=%d", free_cluster);
    
    // Link clusters    
    err = link_cluster(disk, cluster, free_cluster);
    if (err != ENOERR)
        return err;

    *new_cluster = free_cluster;

    CYG_TRACE1(TCL, "new_cluster=%d", free_cluster);
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// find_nth_cluster0()
// Finds nth cluster in chain (ie nth cluster of file).
// Searching from given position.
 
static int
find_nth_cluster0(fatfs_disk_t     *disk,
                  fatfs_data_pos_t *dpos, 
                  cyg_uint32        n,
                  fatfs_tcache_t   *tcache)
{
    cyg_uint32 cluster, cluster_snum;
    int err = ENOERR;
 
    // Trivial case check
    if (dpos->cluster_snum == n)
        return ENOERR;

    // First look in cache
    if (NULL != tcache)
    {
        cyg_uint32 c, ln;
        if (fatfs_tcache_get(disk, tcache, n, &c))
        {
            // Cluster in cache
            dpos->cluster = c;
            dpos->cluster_snum = n;
            CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d in cache", c, n);
            return ENOERR;
        }
        else if (fatfs_tcache_get_last(disk, tcache, &ln, &c))
        {
            // Cluster not in cache - get last
            // in cache and search from there
            dpos->cluster = c;
            dpos->cluster_snum = ln;  
            CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d last in cache", c, ln);
        }
        else
        {
            // Empty cache - put first cluster in
            fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->cluster);
        }
    }
   
    cluster      = dpos->cluster;
    cluster_snum = dpos->cluster_snum;
   
    CYG_TRACE4(TCL, "cluster=%d cluster_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:
                // Oops early last cluster
                CYG_TRACE1(TCL, "chain end 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++;
        if (NULL != tcache)
            fatfs_tcache_set(disk, tcache, cluster_snum, cluster);
        n--;
    }
    
out:
    dpos->cluster      = cluster;
    dpos->cluster_snum = cluster_snum;

    CYG_TRACE2(TCL, "nth cluster=%d cluster_snum=%d", cluster, cluster_snum);
    return err;
}

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

    // EEOF meens that the cluster chain ended early
    if ((err != EEOF) || !(opts & CO_EXTEND))
        return err;
    
    CYG_TRACE2(TCL, "cluster_snum=%d n=%d", dpos->cluster_snum, n);
    
    // Check if one cluster short
    if (dpos->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, dpos->cluster, 
                                      &new_cluster, opts);
        if (err != ENOERR)
            return err;

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

        CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", 
                        dpos->cluster, dpos->cluster_snum);
        
        // Update cache
        if (NULL != tcache)
            fatfs_tcache_set(disk, tcache, dpos->cluster_snum, dpos->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 
// chain then the chain is extended by one cluster.

static int
get_next_cluster(fatfs_disk_t     *disk,
                 fatfs_data_pos_t *dpos,
                 fatfs_tcache_t   *tcache,
                 cluster_opts_t    opts)
{
    int err;

    CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", 
                    dpos->cluster, dpos->cluster_snum);

    err = find_nth_cluster(disk, dpos, dpos->cluster_snum + 1, tcache, opts);

    if (err != ENOERR)
        return err;

    // Update position
    dpos->cluster_pos = 0;
 
    CYG_TRACE2(TCL, "cluster=%d cluster_snum=%d", 
                    dpos->cluster, dpos->cluster_snum);
    
    return ENOERR;
}

// -------------------------------------------------------------------------
// get_data_position_from_off()
// Gets data position from given file offset.
// If CO_EXTEND is specified the file is extended if 
// one cluster too short. 
 
static int 
get_data_position_from_off(fatfs_disk_t     *disk,
                           cyg_uint32        first_cluster, 
                           cyg_uint32        offset, 
                           fatfs_data_pos_t *dpos,
                           fatfs_tcache_t   *tcache,
                           cluster_opts_t    opts)
{
    cyg_uint32 n;
    int err;

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

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

    // Start searching from first cluster
    dpos->cluster      = first_cluster;
    dpos->cluster_snum = 0;

    CYG_TRACE4(TCL, "off=%d first_cluster=%d cluster_pos=%d n=%d\n",
                    offset, first_cluster, dpos->cluster_pos, n);

    err = find_nth_cluster(disk, dpos, n, tcache, opts);

    // Err could be EEOF wich means that the given 
    // offset if out of given file (cluster chain)

    return err;
}

// -------------------------------------------------------------------------
// free_cluster_chain()
// Marks all clusters FREE from given cluster to the last cluster in chain.

static int
free_cluster_chain(fatfs_disk_t *disk, cyg_uint32 start_cluster)
{
    cyg_uint32 c, next_c, tentry;
    bool last;
    int err;

    CYG_TRACE1(TCL, "start_cluster=%d", start_cluster);

    c = next_c = start_cluster;
    last = false;
    while (!last)
    {
        err = read_tentry(disk, c, &tentry);
        if (err != ENOERR)
            return err;

        switch (get_tentry_type(disk, tentry))
        {
            case TENTRY_LAST:
                // Last cluster in chain
                last = true;
                break;
            case TENTRY_REGULAR:
                // Get next cluster in chain
                next_c = get_tentry_next_cluster(disk, tentry);
                break;
            default:
                CYG_TRACE2(TCL, "!!! inconsistant FAT tentry=%x c=%d", 
                                tentry, c);
                return EIO;
        }

        // Set the current tentry to FREE 
        set_tentry_type(disk, &tentry, TENTRY_FREE);
        err = write_tentry(disk, c, &tentry);
        if (err != ENOERR)
            return err;

        // Next cluster in chain
        c = next_c; 
    }

    CYG_TRACE1(TCL, "last_cluster=%d", c);
    
    return ENOERR;
}

//==========================================================================
// FAT dir entry functions 

// -------------------------------------------------------------------------
// print_dentry()
// Prints FAT directory entry. 

#if TDE
static void
print_dentry(fat_dir_entry_t* fde)
{
    if (DENTRY_IS_DELETED(fde))
        diag_printf("FAT: FDE name:    '?%.7s'\n", &fde->name[1]);
    else    
        diag_printf("FAT: FDE name:    '%.8s'\n", fde->name);
    diag_printf("FAT: FDE ext:     '%.3s'\n", fde->ext);
    diag_printf("FAT: FDE attr:     %c%c%c%c%c%c\n", 
                (DENTRY_IS_RDONLY(fde)  ? 'R' : '-'),
                (DENTRY_IS_HIDDEN(fde)  ? 'H' : '-'),
                (DENTRY_IS_SYSTEM(fde)  ? 'S' : '-'),
                (DENTRY_IS_VOLUME(fde)  ? 'V' : '-'),
                (DENTRY_IS_DIR(fde)     ? 'D' : '-'),
                (DENTRY_IS_ARCHIVE(fde) ? 'A' : '-'));
    diag_printf("FAT: FDE crt time: %u\n", fde->crt_time);
    diag_printf("FAT: FDE crt date: %u\n", fde->crt_date);
    diag_printf("FAT: FDE acc date: %u\n", fde->acc_date);
    diag_printf("FAT: FDE wrt time: %u\n", fde->wrt_time);
    diag_printf("FAT: FDE wrt date: %u\n", fde->wrt_date);
    diag_printf("FAT: FDE cluster:  %u\n", fde->cluster);
    diag_printf("FAT: FDE size:     %u\n", fde->size);
}
#endif // TDE

// -------------------------------------------------------------------------
// read_dentry()
// Reads dir entry from disk. 
// If cluster is 0 reads from root dir.
 
static int
read_dentry(fatfs_disk_t     *disk,
            fatfs_data_pos_t *dpos, 
            fat_dir_entry_t  *fde)
{
    unsigned char data[DENTRY_SIZE];
    cyg_uint32 apos;
    int len, err;
   
    // Check if we are reading the root directory
    if (0 == dpos->cluster)
        apos = disk->fat_root_dir_pos + dpos->cluster_pos;
    else
        apos = get_data_disk_apos(disk, dpos->cluster, dpos->cluster_pos);    
   
    CYG_TRACE3(TDE, "cluster=%d pos=%d apos=%d",
                    dpos->cluster, dpos->cluster_pos, apos); 
    
    len = DENTRY_SIZE;
    err = cyg_blib_read(&disk->blib, (void*)data, &len, 0, apos);
    if (err != ENOERR)
        return err;

    GET_BYTES(data, fde->name,     8, 0x00);
    GET_BYTES(data, fde->ext,      3, 0x08);
    GET_BYTE(data,  fde->attr,        0x0B);
    GET_BYTE(data,  fde->nt_reserved, 0x0C);
    GET_BYTE(data,  fde->crt_sec_100, 0x0D);
    GET_WORD(data,  fde->crt_time,    0x0E);

⌨️ 快捷键说明

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