📄 ramfs.c
字号:
typedef cyg_uint8 ramfs_block[CYGNUM_RAMFS_BLOCK_SIZE];
#endif
//==========================================================================
// File and directory node
// This data structure represents a file or directory.
struct ramfs_node
{
mode_t mode; // node type
cyg_ucount32 refcnt; // open file/current dir references
nlink_t nlink; // number of links to this node
size_t size; // size of file in bytes
time_t atime; // last access time
time_t mtime; // last modified time
time_t ctime; // last changed status time
#ifdef CYGPKG_FS_RAM_SIMPLE
// The data storage in this case consists of a single
// malloced memory block, together with its size.
size_t datasize; // size of data block
cyg_uint8 *data; // malloced data buffer
#else
// The data storage in this case consists of arrays of pointers
// to data blocks.
#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
// Directly accessible blocks from the inode.
ramfs_block *direct[CYGNUM_RAMFS_BLOCKS_DIRECT];
#endif
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
// Single level indirection
ramfs_block **indirect1[CYGNUM_RAMFS_BLOCKS_INDIRECT1];
#endif
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
// Two level indirection
ramfs_block ***indirect2[CYGNUM_RAMFS_BLOCKS_INDIRECT2];
#endif
#endif
};
//==========================================================================
// Directory entry.
// Fixed sized entry containing a fragment of the name of a file/directory.
struct ramfs_dirent
{
ramfs_node *node; // pointer to node
unsigned int inuse:1, // entry in use?
first:1, // first directory entry fragment?
last:1, // last directory entry fragment?
namelen:8, // bytes in whole name
fraglen:8; // bytes in name fragment
off_t next; // offset of next dirent
// Name fragment, fills rest of entry.
char name[CYGNUM_RAMFS_DIRENT_SIZE-
sizeof(ramfs_node *)-
sizeof( cyg_uint32)-
sizeof(off_t)];
};
//==========================================================================
// Directory search data
// Parameters for a directory search. The fields of this structure are
// updated as we follow a pathname through the directory tree.
struct ramfs_dirsearch
{
ramfs_node *dir; // directory to search
const char *path; // path to follow
ramfs_node *node; // Node found
const char *name; // last name fragment used
int namelen; // name fragment length
cyg_bool last; // last name in path?
};
typedef struct ramfs_dirsearch ramfs_dirsearch;
//==========================================================================
// Forward defs
static int del_direntry( ramfs_node *dir, const char *name, int namelen );
//==========================================================================
// Block array
// This is used for block allocation when malloc is not being used.
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
# ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY_EXTERN
// Array is defined externally with a user-supplied name
__externC ramfs_block CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
// Translate into a usable common name
#define ramfs_block_array CYGPKG_FS_RAM_BLOCKS_ARRAY_NAME
# else
// Array is defined here
static ramfs_block cyg_ramfs_block_array[CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE];
#define ramfs_block_array cyg_ramfs_block_array
# endif
// Pointer to list of free blocks
static ramfs_block *block_free_list = NULL;
#endif
//==========================================================================
// Block allocation
#ifndef CYGPKG_FS_RAM_SIMPLE
// -------------------------------------------------------------------------
// block_init()
// Initialize the block allocator by chaining them all together on
// block_free_list.
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
static void block_init(void)
{
static cyg_bool initialized = false;
int i;
if( !initialized )
{
for( i = 0; i < CYGNUM_FS_RAM_BLOCKS_ARRAY_SIZE; i++ )
{
ramfs_block *b = &ramfs_block_array[i];
*(ramfs_block **)b = block_free_list;
block_free_list = b;
}
initialized = true;
}
}
#endif
// -------------------------------------------------------------------------
// block_alloc()
// Allocate a block for data storage.
// If we have a block array, just pick the first off the free list.
// If we are mallocing, call malloc() to get it.
static ramfs_block *block_alloc(void)
{
ramfs_block *b;
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
block_init(); // Check blocks are initialized
// pick first block off free list.
b = block_free_list;
// and advance list
if( b != NULL )
block_free_list = *(ramfs_block **)b;
#else
b = malloc(CYGNUM_RAMFS_BLOCK_SIZE);
#endif
// Clear the block to zero if it was allocated
if( b != NULL )
memset( b, 0, CYGNUM_RAMFS_BLOCK_SIZE );
return b;
}
// -------------------------------------------------------------------------
// block_free()
// Free a block. Depending on the configuration send it back to the
// heap or put it back on free list.
static void block_free( ramfs_block *b )
{
#ifdef CYGPKG_FS_RAM_BLOCKS_ARRAY
// Put the block back on the free list
*(ramfs_block **)b = block_free_list;
block_free_list = b;
#else
// Call free() to return it to the memory pool
free( b );
#endif
}
#endif
//==========================================================================
// Node buffer management
// There are two versions of this, one for the _SIMPLE variant and one for
// the _BLOCKS variant. In both cases the interface to this code is via the
// findbuffer_node() and freebuffer_node() functions.
#ifdef CYGPKG_FS_RAM_SIMPLE
//==========================================================================
// SIMPLE buffer management.
// Each node has a data buffer pointer and a size. This buffer is
// realloc()ed as needed.
// -------------------------------------------------------------------------
// findbuffer_node()
// return a pointer to the data at the indicated file position, extending
// the buffer if required.
static int findbuffer_node( ramfs_node *node, // node pointer
off_t pos, // data position to get
cyg_uint8 **buffer, // returned buffer pointer
size_t *size, // returned buffer size
cyg_bool alloc) // extend allocation?
{
if( alloc && (pos >= node->datasize || node->datasize == 0) )
{
// If we are allowed to alloc new data, and we are at the end of the
// current data allocation, or there is no data present, allocate or
// extend the data buffer.
cyg_uint8 *newdata;
if( node->data == NULL )
newdata = malloc( CYGNUM_RAMFS_REALLOC_INCREMENT );
else
newdata = realloc( node->data, pos+CYGNUM_RAMFS_REALLOC_INCREMENT );
if( newdata == NULL ) return ENOSPC;
else memset( newdata + node->datasize, 0,
pos + CYGNUM_RAMFS_REALLOC_INCREMENT - node->datasize );
node->data = newdata;
node->datasize = pos+CYGNUM_RAMFS_REALLOC_INCREMENT;
}
else if( pos > node->datasize )
{
// Indicate end of data.
*size = 0;
return ENOERR;
}
*buffer = node->data+pos;
*size = node->datasize-pos;
return ENOERR;
}
// -------------------------------------------------------------------------
// freebuffer_node()
// Empty out the data storage from the node.
static int freebuffer_node( ramfs_node *node )
{
if( node->data != NULL )
{
free( node->data );
}
node->data = NULL;
node->datasize = 0;
return ENOERR;
}
//==========================================================================
#else
//==========================================================================
// _BLOCKS storage management.
// Data storage in the node is by means of a set of arrays of pointers to
// blocks. The first array points directly to the data blocks. Subsequent
// arrays point to single and double indirect blocks respectively.
// -------------------------------------------------------------------------
// findbuffer_direct()
// Indexes into an array of block pointers and extracts a pointer to the
// data at offset _pos_, allocating new blocks if required.
static int findbuffer_direct( off_t pos,
ramfs_block **blocks,
int nblocks,
cyg_uint8 **buffer,
size_t *size,
cyg_bool alloc)
{
int bi = pos / CYGNUM_RAMFS_BLOCK_SIZE;
int bpos = pos % CYGNUM_RAMFS_BLOCK_SIZE;
ramfs_block *b;
*buffer = NULL;
*size = CYGNUM_RAMFS_BLOCK_SIZE - bpos;
if( bi >= nblocks )
return ENOERR;
b = blocks[bi];
if( b == NULL )
{
// There is no block there. If _alloc_ is true we can fill the
// slot in with a new block. If it is false, we indicate there
// is no block and size indicates where the block would end if
// it existed.
if( alloc )
{
b = block_alloc();
if( b == NULL )
return ENOSPC;
blocks[bi] = b;
}
else return ENOERR;
}
*buffer = &((*b)[bpos]);
return ENOERR;
}
// -------------------------------------------------------------------------
// findbuffer_indirect1()
// Indexes into an array of pointers to blocks containing pointers to
// blocks and extracts a pointer to the data at offset _pos_,
// allocating new blocks if required.
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
static int findbuffer_indirect1( off_t pos,
ramfs_block ***blocks,
int nblocks,
cyg_uint8 **buffer,
size_t *size,
cyg_bool alloc)
{
int bi = pos / RAMFS_INDIRECT1_BLOCK_EXTENT;
int bpos = pos % RAMFS_INDIRECT1_BLOCK_EXTENT;
int err;
cyg_uint8 *b;
size_t sz;
// Use findbuffer_direct() to index and allocate
// the first level indirect block.
err = findbuffer_direct( bi*CYGNUM_RAMFS_BLOCK_SIZE,
(ramfs_block **)blocks,
nblocks,
&b,
&sz,
alloc);
if( err != ENOERR )
return err;
if( sz == 0 )
{
*size = 0;
return ENOERR;
}
// Use findbuffer_direct() on the first level indirect
// block to allocate and return the data pointer.
return findbuffer_direct( bpos,
blocks[bi],
RAMFS_INDIRECT_PER_BLOCK,
buffer,
size,
alloc);
}
#endif
// -------------------------------------------------------------------------
// findbuffer_indirect1()
// Indexes into an array of pointers to blocks containing pointers to
// blocks containing pointers to blocks (!) and extracts a pointer to
// the data at offset _pos_, allocating new blocks if required.
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
static int findbuffer_indirect2( off_t pos,
ramfs_block ****blocks,
int nblocks,
cyg_uint8 **buffer,
size_t *size,
cyg_bool alloc)
{
int bi = pos / RAMFS_INDIRECT2_BLOCK_EXTENT;
int bpos = pos % RAMFS_INDIRECT2_BLOCK_EXTENT;
int err;
cyg_uint8 *b;
size_t sz;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -