📄 fatfs.c
字号:
//==========================================================================
//
// 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 + -