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

📄 fatfs.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
//==========================================================================
//
//      fatfs.c
//
//      FAT file system
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):           Savin Zlobec <savin@elatec.si> (based on ramfs.c)
// Original data:       nickg
// Date:                2003-06-29
// Purpose:             FAT file system
// Description:         This is a FAT filesystem for eCos. 
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <pkgconf/system.h>
#include <pkgconf/hal.h>
#include <pkgconf/io_fileio.h>
#include <pkgconf/fs_fat.h>

#include <cyg/infra/cyg_type.h>   
#include <cyg/infra/cyg_trac.h>        // tracing macros
#include <cyg/infra/cyg_ass.h>         // assertion macros

#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <dirent.h>

#include <stdlib.h>
#include <string.h>

#include <cyg/infra/diag.h>
#include <cyg/fileio/fileio.h>
#include <cyg/io/io.h>
#include <blib/blib.h>
#include <cyg/fs/fatfs.h>

#include "fatfs.h"

//==========================================================================
// Tracing support defines 

#ifdef FATFS_TRACE_FS_OP
# define TFS 1
#else
# define TFS 0
#endif

#ifdef FATFS_TRACE_FILE_OP
# define TFO 1
#else
# define TFO 0
#endif

//==========================================================================
// Forward definitions

// Filesystem operations
static int fatfs_mount  (cyg_fstab_entry *fste, cyg_mtab_entry *mte);
static int fatfs_umount (cyg_mtab_entry *mte);
static int fatfs_open   (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                         int mode, cyg_file *fte);
static int fatfs_unlink (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
static int fatfs_mkdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
static int fatfs_rmdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name);
static int fatfs_rename (cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
                         cyg_dir dir2, const char *name2 );
static int fatfs_link   (cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
                         cyg_dir dir2, const char *name2, int type );
static int fatfs_opendir(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                         cyg_file *fte );
static int fatfs_chdir  (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                         cyg_dir *dir_out );
static int fatfs_stat   (cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                         struct stat *buf);
static int fatfs_getinfo(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                         int key, void *buf, int len );
static int fatfs_setinfo(cyg_mtab_entry *mte, cyg_dir dir, const char *name,
                         int key, void *buf, int len );

// File operations
static int fatfs_fo_read   (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int fatfs_fo_write  (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int fatfs_fo_lseek  (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int fatfs_fo_ioctl  (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
                            CYG_ADDRWORD data);
static int fatfs_fo_fsync  (struct CYG_FILE_TAG *fp, int mode );        
static int fatfs_fo_close  (struct CYG_FILE_TAG *fp);
static int fatfs_fo_fstat  (struct CYG_FILE_TAG *fp, struct stat *buf );
static int fatfs_fo_getinfo(struct CYG_FILE_TAG *fp, int key, 
                            void *buf, int len );
static int fatfs_fo_setinfo(struct CYG_FILE_TAG *fp, int key, 
                            void *buf, int len );

// Directory operations
static int fatfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int fatfs_fo_dirlseek(struct CYG_FILE_TAG *fp, off_t *pos, int whence);

//==========================================================================
// Filesystem table entries

// -------------------------------------------------------------------------
// Fstab entry.

FSTAB_ENTRY(fatfs_fste, "fatfs", 0,
            CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
            fatfs_mount,
            fatfs_umount,
            fatfs_open,
            fatfs_unlink,
            fatfs_mkdir,
            fatfs_rmdir,
            fatfs_rename,
            fatfs_link,
            fatfs_opendir,
            fatfs_chdir,
            fatfs_stat,
            fatfs_getinfo,
            fatfs_setinfo);

// -------------------------------------------------------------------------
// File operations.

static cyg_fileops fatfs_fileops =
{
    fatfs_fo_read,
    fatfs_fo_write,
    fatfs_fo_lseek,
    fatfs_fo_ioctl,
    cyg_fileio_seltrue,
    fatfs_fo_fsync,
    fatfs_fo_close,
    fatfs_fo_fstat,
    fatfs_fo_getinfo,
    fatfs_fo_setinfo
};

// -------------------------------------------------------------------------
// Directory file operations.

static cyg_fileops fatfs_dirops =
{
    fatfs_fo_dirread,
    (cyg_fileop_write *)cyg_fileio_enosys,
    fatfs_fo_dirlseek,
    (cyg_fileop_ioctl *)cyg_fileio_enosys,
    cyg_fileio_seltrue,
    (cyg_fileop_fsync *)cyg_fileio_enosys,
    fatfs_fo_close,
    (cyg_fileop_fstat *)cyg_fileio_enosys,
    (cyg_fileop_getinfo *)cyg_fileio_enosys,
    (cyg_fileop_setinfo *)cyg_fileio_enosys
};

// -------------------------------------------------------------------------
// Directory search data
// Parameters for a directory search. The fields of this structure are
// updated as we follow a pathname through the directory tree.

typedef struct fatfs_dirsearch_s
{
    fatfs_disk_t        *disk;     // Disk info 
    fatfs_node_t        *dir;      // Directory to search
    const char          *path;     // Path to follow
    fatfs_node_t        *node;     // Node found
    const char          *name;     // Last name fragment used
    int                  namelen;  // Name fragment length
    cyg_bool             last;     // Last name in path?
} fatfs_dirsearch_t;

// -------------------------------------------------------------------------
// FATFS file descriptor data

typedef struct fatfs_fd_s
{
    fatfs_node_t      *node;
    fatfs_data_pos_t   pos;
} fatfs_fd_t;

static fatfs_fd_t  fatfs_fds_base[CYGNUM_FILEIO_NFD];
static fatfs_fd_t *fatfs_fds_pool[CYGNUM_FILEIO_NFD];
static cyg_uint32  fatfs_fds_free_cnt;

//==========================================================================

#if TFS
static void 
print_disk_info(fatfs_disk_t *disk)
{
    diag_printf("FAT: sector size:        %u\n", disk->sector_size);
    diag_printf("FAT: cluster size:       %u\n", disk->cluster_size);
    diag_printf("FAT: FAT table position: %u\n", disk->fat_tbl_pos);
    diag_printf("FAT: FAT table num ent:  %u\n", disk->fat_tbl_nents);
    diag_printf("FAT: FAT table size:     %u\n", disk->fat_tbl_size);
    diag_printf("FAT: FAT tables num:     %u\n", disk->fat_tbls_num);
    diag_printf("FAT: FAT root dir pos:   %u\n", disk->fat_root_dir_pos);
    diag_printf("FAT: FAT root dir nents: %u\n", disk->fat_root_dir_nents);
    diag_printf("FAT: FAT root dir size:  %u\n", disk->fat_root_dir_size);
    diag_printf("FAT: FAT data position:  %u\n", disk->fat_data_pos);
}
#endif

static void
init_fatfs_fds(void)
{
    static bool initialized = false;

    int i;

    if (initialized)
        return;
    
    initialized = true;
    
    for (i = 0; i < CYGNUM_FILEIO_NFD; i++)
    {
        fatfs_fds_pool[i] = &fatfs_fds_base[i];    
    }
    fatfs_fds_free_cnt = i;
}

static fatfs_fd_t *
alloc_fatfs_fd(fatfs_disk_t *disk, fatfs_node_t *node)
{
    fatfs_fd_t *fd = NULL;

    if (fatfs_fds_free_cnt > 0)
    {
        fd = fatfs_fds_pool[--fatfs_fds_free_cnt];

        fd->node = node;
        fatfs_initpos(disk, &node->dentry, &fd->pos);
    }
    
    return fd;
}

static void
free_fatfs_fd(fatfs_fd_t *fd)
{
    fatfs_fds_pool[fatfs_fds_free_cnt++] = fd;
}

static void
init_dirsearch(fatfs_dirsearch_t *ds,
               fatfs_disk_t      *disk, 
               fatfs_node_t      *dir,
               const char        *name)
{
    ds->disk = disk;
    
    if (NULL == dir)
        ds->dir = disk->root;
    else
        ds->dir = dir;
    
    ds->path    = name;
    ds->node    = ds->dir;
    ds->namelen = 0;
    ds->last    = false;
}

static int
find_direntry(fatfs_dirsearch_t *ds)
{
    fatfs_dir_entry_t  dentry;
    fatfs_data_pos_t   pos;
    int                err;

    CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name);

    // First check the cache
    
    ds->node = fatfs_node_find(ds->disk, 
                               ds->name, 
                               ds->namelen, 
                               ds->dir->dentry.cluster);

    if (ds->node != NULL)
    {
        // Dir entry found in cache
        
        CYG_TRACE0(TFS, "dir entry found in cache");

        fatfs_node_touch(ds->disk, ds->node);
        return ENOERR;
    }

    // Dir entry not in cache - search the current dir

    fatfs_initpos(ds->disk, &ds->dir->dentry, &pos);

    while (true)
    {  
        // Read next dir entry 
        
        err = fatfs_read_dir_entry(ds->disk, &ds->dir->dentry, &pos, &dentry);
        if (err != ENOERR)
            return (err == EEOF ? ENOERR : err);

        // Compare filenames
        
        if ('\0' == dentry.filename[ds->namelen] &&
               0 == strncasecmp(dentry.filename, ds->name, ds->namelen))
        {
            // Dir entry found - allocate new node and return

            CYG_TRACE0(TFS, "dir entry found");

            ds->node = fatfs_node_alloc(ds->disk, &dentry);
            if (NULL == ds->node)
                return EMFILE;

            return ENOERR;
        }
    }
}

static int 
find_entry(fatfs_dirsearch_t *ds)
{
    const char  *name     = ds->path;
    const char  *n        = name;
    char         namelen  = 0;
    int          err;
    
    if( !S_ISDIR(ds->dir->dentry.mode) )
    {
        CYG_TRACE1(TFS, "entry '%s' not dir", ds->dir->dentry.filename);
        return ENOTDIR;
    }
    
    // Isolate the next element of the path name
    while (*n != '\0' && *n != '/')
        n++, namelen++;

    // If we terminated on a NUL, set last flag
    if (*n == '\0')
        ds->last = true;

    // Update name in dirsearch object
    ds->name    = name;
    ds->namelen = namelen;

    err = find_direntry(ds);
    if (err != ENOERR)
        return err;

    CYG_TRACE2(TFS, "entry '%s' %s", name, (ds->node ? "found" : "not found"));
    
    if (ds->node != NULL)
       return ENOERR;
    else
       return ENOENT; 
}

static int
fatfs_find(fatfs_dirsearch_t *ds)
{
    int err;

    CYG_TRACE1(TFS, "find path='%s'", ds->path);
    
    // Short circuit empty paths
    if (*(ds->path) == '\0')
        return ENOERR;
    
    // Iterate down directory tree until we find the object we want
    for(;;)
    {
        err = find_entry(ds);
        
        if (err != ENOERR)
            return err;
        
        if (ds->last)
        {
            CYG_TRACE0(TFS, "entry found");
            return ENOERR;
        }

        // Update dirsearch object to search next directory
        ds->dir   = ds->node;
        ds->path += ds->namelen;
        
        // Skip dirname separators
        if (*(ds->path) == '/') ds->path++;
        
        CYG_TRACE1(TFS, "find path to go='%s'", ds->path);
    }
}

//==========================================================================
// Filesystem operations

// -------------------------------------------------------------------------
// fatfs_mount()
// Process a mount request. This mainly creates a root for the
// filesystem.

static int 
fatfs_mount(cyg_fstab_entry *fste, cyg_mtab_entry *mte)
{
    cyg_io_handle_t     dev_h;
    fatfs_disk_t       *disk;
    fatfs_dir_entry_t   root_dentry;
    Cyg_ErrNo           err;

    CYG_TRACE2(TFS, "mount fste=%p mte=%p", fste, mte);

    init_fatfs_fds();
    
    CYG_TRACE1(TFS, "looking up disk device '%s'", mte->devname);
    
    err = cyg_io_lookup(mte->devname, &dev_h);
    if (err != ENOERR)
        return err;

    disk = (fatfs_disk_t *)malloc(sizeof(fatfs_disk_t));
    if (NULL == disk)
        return ENOMEM;
        
    CYG_TRACE0(TFS, "initializing block cache"); 

    disk->bcache_mem = (cyg_uint8 *)malloc(CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE);
    if (NULL == disk->bcache_mem)
    {
        free(disk);
        return ENOMEM;
    }
    // FIXME: get block size from disk device
    err = cyg_blib_io_create(dev_h, disk->bcache_mem, 
            CYGNUM_FS_FAT_BLOCK_CACHE_MEMSIZE, 512, &disk->blib);
    if (err != ENOERR)
    {
        free(disk->bcache_mem);
        free(disk);
        return err;
    }
    
    disk->dev_h = dev_h;

    CYG_TRACE0(TFS, "initializing disk");
    
    err = fatfs_init(disk);
    if (err != ENOERR)
    {
        cyg_blib_delete(&disk->blib);
        free(disk->bcache_mem);
        free(disk);
        return err;
    }
   
#if TFS    
    print_disk_info(disk);
#endif

    CYG_TRACE0(TFS, "initializing node cache");

    fatfs_node_cache_init(disk);
    
    CYG_TRACE0(TFS, "initializing root node");
    
    fatfs_get_root_dir_entry(disk, &root_dentry);
    
    disk->root = fatfs_node_alloc(disk, &root_dentry);

    fatfs_node_ref(disk, disk->root);
    
    mte->root = (cyg_dir)disk->root;
    mte->data = (CYG_ADDRWORD)disk;

    CYG_TRACE0(TFS, "disk mounted");

⌨️ 快捷键说明

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