📄 ramfs.c
字号:
// 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_indirect1() on the first level indirect block to
// index and allocate the next level indirect block and the data
// block.
return findbuffer_indirect1( bpos,
blocks[bi],
RAMFS_INDIRECT_PER_BLOCK,
buffer,
size,
alloc);
}
#endif
// -------------------------------------------------------------------------
// findbuffer_node()
// Depending on the offset and configuration, call the appropriate
// function to get the buffer pointer.
static int findbuffer_node( ramfs_node *node,
off_t pos,
cyg_uint8 **buffer,
size_t *size,
cyg_bool alloc)
{
#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
if( pos < RAMFS_DIRECT_MAX )
return findbuffer_direct( pos,
node->direct,
CYGNUM_RAMFS_BLOCKS_DIRECT,
buffer,
size,
alloc);
#endif
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
if( pos < RAMFS_INDIRECT1_MAX )
return findbuffer_indirect1( pos - RAMFS_DIRECT_MAX,
node->indirect1,
CYGNUM_RAMFS_BLOCKS_INDIRECT1,
buffer,
size,
alloc);
#endif
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
if( pos < RAMFS_INDIRECT2_MAX )
return findbuffer_indirect2( pos - RAMFS_INDIRECT1_MAX,
node->indirect2,
CYGNUM_RAMFS_BLOCKS_INDIRECT2,
buffer,
size,
alloc);
#endif
return ENOSPC;
}
// -------------------------------------------------------------------------
// freeblock_list()
// Free a list of data blocks.
static void freeblock_list( ramfs_block *blocks[],int nblocks )
{
int i;
for( i = 0; i < nblocks ; i++ )
{
if( blocks[i] != NULL )
{
block_free( blocks[i] );
blocks[i] = NULL;
}
}
}
// -------------------------------------------------------------------------
// freebuffer_node()
// Free all the data blocks in the node and clear the pointers.
static int freebuffer_node( ramfs_node *node )
{
#if CYGNUM_RAMFS_BLOCKS_DIRECT > 0
freeblock_list( node->direct, CYGNUM_RAMFS_BLOCKS_DIRECT );
#endif
#if CYGNUM_RAMFS_BLOCKS_INDIRECT1 > 0
{
int i;
for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT1 ; i++ )
{
if( node->indirect1[i] != NULL )
{
freeblock_list( (ramfs_block **)node->indirect1[i], RAMFS_INDIRECT_PER_BLOCK );
block_free( (ramfs_block *)node->indirect1[i] );
node->indirect1[i] = NULL;
}
}
}
#endif
#if CYGNUM_RAMFS_BLOCKS_INDIRECT2 > 0
{
int i;
for( i = 0; i < CYGNUM_RAMFS_BLOCKS_INDIRECT2 ; i++ )
{
if( node->indirect2[i] != NULL )
{
ramfs_block ***b = node->indirect2[i];
int j;
for( j = 0; j < RAMFS_INDIRECT_PER_BLOCK ; j++ )
{
if( b[j] != NULL )
{
freeblock_list( (ramfs_block **)b[j], RAMFS_INDIRECT_PER_BLOCK );
block_free( (ramfs_block *)b[j] );
b[j] = NULL;
}
}
block_free( (ramfs_block *)node->indirect2[i] );
node->indirect2[i] = NULL;
}
}
}
#endif
return ENOERR;
}
//==========================================================================
#endif
//==========================================================================
// Node allocation
// -------------------------------------------------------------------------
// alloc_node()
// Allocate a node and initialize it.
// For the _SIMPLE allocation option, we just malloc it. For the
// _BLOCKS option we allocate a block and use that. In theory we could
// pack several nodes into a single block, but we don't at present due
// to sheer lazyness.
static ramfs_node *alloc_node( mode_t mode )
{
#ifdef CYGPKG_FS_RAM_SIMPLE
ramfs_node *node = malloc( sizeof( ramfs_node ) );
if( node == NULL )
return NULL;
#else
ramfs_block *b = block_alloc();
ramfs_node *node;
if( b == NULL )
return NULL;
node = (ramfs_node *)b;
#endif
memset( node, 0, sizeof(ramfs_node) );
node->mode = mode;
node->refcnt = 0;
node->nlink = 0;
node->size = 0;
node->atime =
node->mtime =
node->ctime = cyg_timestamp();
#ifdef CYGPKG_FS_RAM_SIMPLE
node->datasize = 0;
node->data = NULL;
#else
// The node is already all zero
#endif
return node;
}
// -------------------------------------------------------------------------
// free_node()
// Release a node either back to the free pool or back into the block
// pool.
static void free_node( ramfs_node *node )
{
#ifdef CYGPKG_FS_RAM_SIMPLE
free( node );
#else
block_free( (ramfs_block *)node );
#endif
}
//==========================================================================
// Ref count and nlink management
// -------------------------------------------------------------------------
// dec_refcnt()
// Decrment the reference count on a node. If this makes the ref count
// zero, and the number of links is either zero for a file or one for
// a node, then this node is detached from the directory tree and can
// be freed.
static int dec_refcnt( ramfs_node *node )
{
int err = ENOERR;
node->refcnt--;
if( node->refcnt == 0 &&
((S_ISREG(node->mode) && node->nlink == 0 ) ||
(S_ISDIR(node->mode) && node->nlink == 1) )
)
{
// This node it now totally detached from the directory tree,
// so delete it.
if( S_ISDIR(node->mode) )
{
del_direntry( node, ".", 1 );
del_direntry( node, "..", 2 );
}
err = freebuffer_node( node );
if( err == ENOERR )
free_node( node );
}
return err;
}
// -------------------------------------------------------------------------
// dec_nlink()
// Decrement a node's link count. Since this has to do all the same
// work as dec_refcnt() we implement this using that function by
// essentially transferring the count to refcnt and then decrement
// that.
static int dec_nlink( ramfs_node *node )
{
node->refcnt++;
node->nlink--;
return dec_refcnt( node );
}
//==========================================================================
// Directory operations
// -------------------------------------------------------------------------
// add_direntry()
// Add an entry to a directory. This is added as a chain of entry
// fragments until the name is exhausted.
static int add_direntry( ramfs_node *dir, // dir to add to
const char *name, // name to add
int namelen, // length of name
ramfs_node *node // node to reference
)
{
off_t pos = 0;
ramfs_dirent *d = NULL, *dp = NULL;
cyg_bool isfirst = true;
// Loop inserting fragments of the name into the directory until we
// have found a home for them all.
while( namelen > 0 )
{
int fraglen = namelen;
if( fraglen > sizeof(d->name) )
fraglen = sizeof(d->name);
// Find a free fragment
for(;;)
{
cyg_uint8 *buf;
size_t size;
int err = findbuffer_node( dir, pos, &buf, &size, true );
if( err != ENOERR ) return err;
d = (ramfs_dirent *)buf;
if( size < sizeof(ramfs_dirent) || d->inuse )
{
pos += sizeof(ramfs_dirent);
continue;
}
break;
}
// d now points to a free dirent structure
d->node = node;
d->inuse = 1;
d->first = isfirst;
d->namelen = namelen;
d->fraglen = fraglen;
if( dp ) dp->next = pos;
memcpy( d->name, name, fraglen );
name += fraglen;
namelen -= fraglen;
pos += sizeof(ramfs_dirent);
dp = d;
isfirst = false;
}
d->last = 1; // Mark last fragment
// Update directory times
dir->mtime =
dir->ctime = cyg_timestamp();
// Extend dir size if necessary
if( pos > dir->size )
dir->size = pos;
// Count the new link
node->nlink++;
return ENOERR;
}
// -------------------------------------------------------------------------
// find_direntry()
// Find a directory entry for the name and return a pointer to the first
// entry fragment.
static ramfs_dirent *find_direntry( ramfs_node *dir, const char *name, int namelen )
{
ramfs_dirent *first = NULL;
off_t pos = 0;
int err;
// Loop over all the entries until a match is found or we run out
// of data.
while( pos < dir->size )
{
const char *frag = name;
ramfs_dirent *d;
cyg_uint8 *buf;
size_t size;
// look for a first name fragment
for(;;)
{
err = findbuffer_node( dir, pos, &buf, &size, false );
if( err != ENOERR || size == 0)
return NULL;
d = (ramfs_dirent *)buf;
if( size < sizeof(ramfs_dirent) || !d->inuse || !d->first )
{
pos += sizeof(ramfs_dirent);
if ( pos < dir->size )
continue;
// End if directory, didn't find it.
return NULL;
}
break;
}
// Here we have got a first fragment of a name, check it
// against the name we are looking for. First check that they
// are the same length.
if( d->namelen == namelen )
{
// We have a potential candidate here...
first = d; // Save it for later
// Now check that all the name fragments match
for(;;)
{
int fraglen = namelen-(frag-name);
if( fraglen > d->fraglen )
fraglen = d->fraglen;
// compare strings, if different, look for another
if( memcmp( frag, d->name, fraglen ) != 0 ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -