📄 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 <stdio.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 <Nls.h>
#include "fatfs.h"
#define _U 0x01 /* upper */
#define _L 0x02 /* lower */
#define _D 0x04 /* digit */
#define _C 0x08 /* cntrl */
#define _P 0x10 /* punct */
#define _S 0x20 /* white space (space/lf/tab) */
#define _X 0x40 /* hex digit */
#define _SP 0x80 /* hard space (0x20) */
//==========================================================================
// 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
static unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P, /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U, /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L, /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L, /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L}; /* 240-255 */
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define isalnum(c) ((__ismask(c)&(_U|_L|_D)) != 0)
#define isalpha(c) ((__ismask(c)&(_U|_L)) != 0)
#define iscntrl(c) ((__ismask(c)&(_C)) != 0)
#define isdigit(c) ((__ismask(c)&(_D)) != 0)
#define isgraph(c) ((__ismask(c)&(_P|_U|_L|_D)) != 0)
#define islower(c) ((__ismask(c)&(_L)) != 0)
#define isprint(c) ((__ismask(c)&(_P|_U|_L|_D|_SP)) != 0)
#define ispunct(c) ((__ismask(c)&(_P)) != 0)
#define isspace(c) ((__ismask(c)&(_S)) != 0)
#define isupper(c) ((__ismask(c)&(_U)) != 0)
#define isxdigit(c) ((__ismask(c)&(_D|_X)) != 0)
#define isascii(c) (((unsigned char)(c))<=0x7f)
#define toascii(c) (((unsigned char)(c))&0x7f)
//==========================================================================
// 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;
struct nls_table* fatfs_utf8_table=NULL;
//==========================================================================
#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 fatfs_dir_entry_t limit_dentry;
static int
find_direntry(fatfs_dirsearch_t *ds)
{
fatfs_data_pos_t pos;
int err;
CYG_TRACE1(TFS, "searching for dir entry '%s'", ds->name);
// First check the cache
memset(&limit_dentry,0,sizeof(fatfs_dir_entry_t));
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, &limit_dentry);
if (err != ENOERR)
return (err == EEOF ? ENOERR : err);
// Compare filenames
if (('\0' == limit_dentry.filename[ds->namelen] &&
0 == strncasecmp(limit_dentry.filename, ds->name, ds->namelen))||
(0==limit_dentry.longfilename[ds->namelen]&&
0 == strncasecmp(limit_dentry.longfilename, 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, &limit_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -