📄 ramfs.c
字号:
//==========================================================================
//
// ramfs.c
//
// RAM file system
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 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): nickg
// Contributors: nickg
// Date: 2000-07-25
// Purpose: RAM file system
// Description: This is a RAM filesystem for eCos. It attempts to
// provide full POSIX-compatible filesystem behaviour
// while at the same time being efficient in terms of
// time and space used.
//
//
//####DESCRIPTIONEND####
//
//==========================================================================
//
// General Description
// ===================
//
// This is an implementation of a RAM filesystem for eCos. Its goal is
// to provide a working example of a filesystem that provides most of
// the required POSIX functionality. And obviously it may also be
// useful in its own right.
//
//
// Nodes
// -----
//
// All files and directories are represented by node objects. Each
// ramfs_node structure contains the following fields:
//
// mode - Node type, file or directory.
// refcnt - Number of references to this node. For files each open counts as
// a reference and for directories a node is referenced when it is made
// current directory, or is opened for reading.
// nlink - Number of links to this node. Each directory entry that references
// this node is a link.
// size - Size of the data in this node in bytes.
// atime - Last time this node was accessed.
// mtime - Last time the data in this node was modified.
// ctime - Last time the status information in this node was changed.
//
// The data storage in a node is controlled by the configuration and
// can take two forms. These will be described later.
//
// Directories
// -----------
//
// A directory is a node whose data is a list of directory entries. To
// simplify management of these, long directory entries are split into
// a chain of fixed size ramfs_dirent structures. These contain the
// following fields:
//
// node - Pointer to node referenced by this entry. This is present in
// every directory entry fragment
// inuse - Set to 1 if this entry is in use, zero if it is free.
// first - Set to 1 if this is the first fragment of a directory entry.
// last - Set to 1 if this is the last fragment of a directory entry.
// namelen - The size of the whole file name.
// fraglen - The number of bytes of the file name that are stored in this
// fragment.
// next - The offset of the next fragment of this directory entry.
// name - The characters of the fragment of the file name stored in this
// entry.
//
// Small file names are stored in a single fragment. Longer names are
// stored in a chain of fragments.
//
// Data Storage
// ------------
//
// Two data storage mechanisms may be configured, the SIMPLE and the
// BLOCKS mechanisms.
//
// SIMPLE Data Storage
// ~~~~~~~~~~~~~~~~~~~
//
// This mechanism simply uses malloc() and free() to allocate the
// memory for both nodes and file data. File data is stored in a
// single malloced vector that is realloced as necessary to acquire
// more space.
//
// The advantage of this approach is that the RAM filesystem only uses
// as much memory as it needs, the rest is available for use by other
// components. It also requires much simpler data structures and code
// in the filesystem to manage. However, if any files get to be a
// significant proportion of the size of the heap, there is the danger
// that fragmentation will prevent any further extension of some
// files, even if there is enough memory in total. It also requires an
// implementation of malloc() to be present. If this needs to be
// present for other components,then this is not a significant
// overhead, but including it just for use by this filesystem
// represents a major addition of code and data structures.
//
//
// BLOCKS Data Storage
// ~~~~~~~~~~~~~~~~~~~
//
// This mechanism divides the memory used for file storage into fixed
// sized blocks. These blocks may either be allocated using
// malloc()/free(), or may be obtained from a array of blocks reserved
// for the purpose. Configuration allows the block size to be
// selected, as well as the allocation mechanism, and in the case of a
// block array, whether it is defined here or by an external
// component.
//
// Data storage in nodes is arranges in three arrays of pointers to
// blocks. The first array points directly to data blocks, the second
// to blocks which themselves contain pointers to data blocks, and the
// third to blocks which contain pointers to blocks which contain
// pointers to data blocks. In the default configuration These last
// two arrays have only one element each.
//
// The following shows how the data is arranged in a fully populated
// file with a 256 byte block size using the default configuration.
//
// Node
// ~ ~
// | |
// | |
// +------------+
// | *------+--------> data block 0
// +------------+
// | *------+--------> data block 1
// +------------+
// | *------+--------> data block 2
// +------------+
// | *------+--------> data block 3
// +------------+
// | *------+--------> data block 4
// +------------+
// | *------+--------> data block 5
// +------------+
// | *------+--------> data block 6
// +------------+
// | *------+--------> data block 7
// +------------+
// | *------+--------> +------------+
// +------------+ | *------+--------> data block 8
// | *------+----+ +------------+
// +------------+ | | |
// | ~ ~
// | | |
// | +------------+
// | | *------+--------> data block 71
// | +------------+
// |
// +---->+------------+ +------------+
// | *------+-------->| *------+---->data block 72
// +------------+ +------------+
// | | | |
// ~ ~ ~ ~
// | | | |
// +------------+ +------------+
// | *------+---+ | *------+----> data block 135
// +------------+ | +------------+
// |
// | +------------+
// +---->| *------+----> data block 4104
// +------------+
// | |
// ~ ~
// | |
// +------------+
// | *------+----> data block 4167
// +------------+
//
//
//
// The advantages of this approach are that, first, memory usage is
// divided into discreet fixed size blocks which are easier to
// manage. When using malloc() to allocate them, they will fit into
// any free memory of at least the right size. Using the block array
// option removes the need to have a malloc() implementation at all.
//
// The disadvantages of this mechanism are that, first, when using
// malloc() to allocate blocks, the per-block memory allocator
// overhead is paid for each block, rather than per file. This may
// result in less memory overall being available for data
// storage. When using the block array, it is permanently reserved for
// use by the ram filesystem, and is not available for use by other
// components.
//
//==========================================================================
#include <pkgconf/system.h>
#include <pkgconf/hal.h>
#include <pkgconf/kernel.h>
#include <pkgconf/io_fileio.h>
#include <pkgconf/fs_ram.h>
#include <cyg/kernel/ktypes.h> // base kernel types
#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/fileio/fileio.h>
#include <cyg/kernel/kapi.h>
#include <cyg/infra/diag.h>
//==========================================================================
// Sizes derived from configuration
// -------------------------------------------------------------------------
// Simple malloc based allocator parameters
#ifdef CYGPKG_FS_RAM_SIMPLE
#define RAMFS_FILESIZE_MAX UINT_MAX
#else
// -------------------------------------------------------------------------
// Block allocator parameters
// The number of nodes per block
#define RAMFS_NODES_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_node))
// The number of indirect pointers that can be stored in a single data block
#define RAMFS_INDIRECT_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_block *))
// The number of directory entries that can be stored in a single data block
#define RAMFS_DIRENT_PER_BLOCK (CYGNUM_RAMFS_BLOCK_SIZE/sizeof(ramfs_dirent))
// Number of bytes contained in a one level indirect block
#define RAMFS_INDIRECT1_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
CYGNUM_RAMFS_BLOCK_SIZE)
// number of bytes contained in a two level indirect block
#define RAMFS_INDIRECT2_BLOCK_EXTENT (RAMFS_INDIRECT_PER_BLOCK* \
RAMFS_INDIRECT_PER_BLOCK* \
CYGNUM_RAMFS_BLOCK_SIZE)
// The maximum data offset for data directly accessed from the node
#define RAMFS_DIRECT_MAX (CYGNUM_RAMFS_BLOCKS_DIRECT*CYGNUM_RAMFS_BLOCK_SIZE)
// The maximum data offset for data accessed from the single level indirect blocks
#define RAMFS_INDIRECT1_MAX (RAMFS_DIRECT_MAX+ \
(CYGNUM_RAMFS_BLOCKS_INDIRECT1* \
RAMFS_INDIRECT1_BLOCK_EXTENT))
// The maximum data offset for data accessed from the two level indirect blocks
#define RAMFS_INDIRECT2_MAX (RAMFS_INDIRECT1_MAX+ \
(CYGNUM_RAMFS_BLOCKS_INDIRECT2* \
RAMFS_INDIRECT2_BLOCK_EXTENT))
// The maximum size of a file
#define RAMFS_FILESIZE_MAX RAMFS_INDIRECT2_MAX
#endif
//==========================================================================
// Forward definitions
// Filesystem operations
static int ramfs_mount ( cyg_fstab_entry *fste, cyg_mtab_entry *mte );
static int ramfs_umount ( cyg_mtab_entry *mte );
static int ramfs_open ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int mode, cyg_file *fte );
static int ramfs_unlink ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int ramfs_mkdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int ramfs_rmdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name );
static int ramfs_rename ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2 );
static int ramfs_link ( cyg_mtab_entry *mte, cyg_dir dir1, const char *name1,
cyg_dir dir2, const char *name2, int type );
static int ramfs_opendir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_file *fte );
static int ramfs_chdir ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
cyg_dir *dir_out );
static int ramfs_stat ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
struct stat *buf);
static int ramfs_getinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
static int ramfs_setinfo ( cyg_mtab_entry *mte, cyg_dir dir, const char *name,
int key, void *buf, int len );
// File operations
static int ramfs_fo_read (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int ramfs_fo_write (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int ramfs_fo_lseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
static int ramfs_fo_ioctl (struct CYG_FILE_TAG *fp, CYG_ADDRWORD com,
CYG_ADDRWORD data);
static int ramfs_fo_fsync (struct CYG_FILE_TAG *fp, int mode );
static int ramfs_fo_close (struct CYG_FILE_TAG *fp);
static int ramfs_fo_fstat (struct CYG_FILE_TAG *fp, struct stat *buf );
static int ramfs_fo_getinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
static int ramfs_fo_setinfo (struct CYG_FILE_TAG *fp, int key, void *buf, int len );
// Directory operations
static int ramfs_fo_dirread (struct CYG_FILE_TAG *fp, struct CYG_UIO_TAG *uio);
static int ramfs_fo_dirlseek (struct CYG_FILE_TAG *fp, off_t *pos, int whence );
//==========================================================================
// Filesystem table entries
// -------------------------------------------------------------------------
// Fstab entry.
// This defines the entry in the filesystem table.
// For simplicity we use _FILESYSTEM synchronization for all accesses since
// we should never block in any filesystem operations.
FSTAB_ENTRY( ramfs_fste, "ramfs", 0,
CYG_SYNCMODE_FILE_FILESYSTEM|CYG_SYNCMODE_IO_FILESYSTEM,
ramfs_mount,
ramfs_umount,
ramfs_open,
ramfs_unlink,
ramfs_mkdir,
ramfs_rmdir,
ramfs_rename,
ramfs_link,
ramfs_opendir,
ramfs_chdir,
ramfs_stat,
ramfs_getinfo,
ramfs_setinfo);
// -------------------------------------------------------------------------
// File operations.
// This set of file operations are used for normal open files.
static cyg_fileops ramfs_fileops =
{
ramfs_fo_read,
ramfs_fo_write,
ramfs_fo_lseek,
ramfs_fo_ioctl,
cyg_fileio_seltrue,
ramfs_fo_fsync,
ramfs_fo_close,
ramfs_fo_fstat,
ramfs_fo_getinfo,
ramfs_fo_setinfo
};
// -------------------------------------------------------------------------
// Directory file operations.
// This set of operations are used for open directories. Most entries
// point to error-returning stub functions. Only the read, lseek and
// close entries are functional.
static cyg_fileops ramfs_dirops =
{
ramfs_fo_dirread,
(cyg_fileop_write *)cyg_fileio_enosys,
ramfs_fo_dirlseek,
(cyg_fileop_ioctl *)cyg_fileio_enosys,
cyg_fileio_seltrue,
(cyg_fileop_fsync *)cyg_fileio_enosys,
ramfs_fo_close,
(cyg_fileop_fstat *)cyg_fileio_enosys,
(cyg_fileop_getinfo *)cyg_fileio_enosys,
(cyg_fileop_setinfo *)cyg_fileio_enosys
};
//==========================================================================
// Data typedefs
// Some forward typedefs for the main data structures.
struct ramfs_node;
typedef struct ramfs_node ramfs_node;
struct ramfs_dirent;
typedef struct ramfs_dirent ramfs_dirent;
#ifndef CYGPKG_FS_RAM_SIMPLE
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -