mirror of
https://github.com/apache/nuttx.git
synced 2026-06-04 14:53:47 +08:00
Added opendir, readdir, closedir, etc.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@62 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
+85
-338
@@ -33,10 +33,6 @@
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
/************************************************************
|
||||
* Compilation Switches
|
||||
************************************************************/
|
||||
|
||||
/************************************************************
|
||||
* Included Files
|
||||
************************************************************/
|
||||
@@ -56,9 +52,6 @@
|
||||
* Definitions
|
||||
************************************************************/
|
||||
|
||||
#define INODE_SEMGIVE() \
|
||||
sem_post(&tree_sem)
|
||||
|
||||
/************************************************************
|
||||
* Private Variables
|
||||
************************************************************/
|
||||
@@ -75,21 +68,9 @@ FAR struct inode *root_inode = NULL;
|
||||
* Private Functions
|
||||
************************************************************/
|
||||
|
||||
static void _inode_semtake(void)
|
||||
{
|
||||
/* Take the semaphore (perhaps waiting) */
|
||||
|
||||
while (sem_wait(&tree_sem) != 0)
|
||||
{
|
||||
/* The only case that an error should occr here is if
|
||||
* the wait was awakened by a signal.
|
||||
*/
|
||||
|
||||
ASSERT(*get_errno_ptr() == EINTR);
|
||||
}
|
||||
}
|
||||
|
||||
#define _inode_semgive(void) sem_post(&tree_sem)
|
||||
/************************************************************
|
||||
* Name: _inode_compare
|
||||
************************************************************/
|
||||
|
||||
static int _inode_compare(const char *fname,
|
||||
FAR struct inode *node)
|
||||
@@ -152,49 +133,79 @@ static int _inode_compare(const char *fname,
|
||||
}
|
||||
}
|
||||
|
||||
static int _inode_namelen(const char *name)
|
||||
{
|
||||
const char *tmp = name;
|
||||
while(*tmp && *tmp != '/') tmp++;
|
||||
return tmp - name;
|
||||
}
|
||||
/************************************************************
|
||||
* Public Functions
|
||||
************************************************************/
|
||||
|
||||
static void _inode_namecpy(char *dest, const char *src)
|
||||
{
|
||||
while(*src && *src != '/') *dest++ = *src++;
|
||||
*dest='\0';
|
||||
}
|
||||
/************************************************************
|
||||
* Name: fs_initialize
|
||||
*
|
||||
* Description:
|
||||
* This is called from the OS initialization logic to configure
|
||||
* the file system.
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
static const char *_inode_nextname(const char *name)
|
||||
void fs_initialize(void)
|
||||
{
|
||||
while (*name && *name != '/') name++;
|
||||
if (*name) name++;
|
||||
return name;
|
||||
}
|
||||
/* Initialize the semaphore to one (to support one-at-
|
||||
* a-time access to the inode tree).
|
||||
*/
|
||||
|
||||
static FAR struct inode *_inode_alloc(const char *name,
|
||||
struct file_operations *fops,
|
||||
mode_t mode, void *private)
|
||||
{
|
||||
int namelen = _inode_namelen(name);
|
||||
FAR struct inode *node = (FAR struct inode*)malloc(FSNODE_SIZE(namelen));
|
||||
if (node)
|
||||
{
|
||||
node->i_peer = NULL;
|
||||
node->i_child = NULL;
|
||||
node->i_ops = fops;
|
||||
#ifdef CONFIG_FILE_MODE
|
||||
node->i_mode = mode;
|
||||
(void)sem_init(&tree_sem, 0, 1);
|
||||
|
||||
/* Initialize files array (if it is used) */
|
||||
|
||||
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
|
||||
if (files_initialize != NULL)
|
||||
#endif
|
||||
node->i_private = private;
|
||||
_inode_namecpy(node->i_name, name);
|
||||
{
|
||||
files_initialize();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static FAR struct inode *_inode_find(const char **path,
|
||||
FAR struct inode **peer,
|
||||
FAR struct inode **parent)
|
||||
/************************************************************
|
||||
* Name: inode_semtake
|
||||
************************************************************/
|
||||
|
||||
void inode_semtake(void)
|
||||
{
|
||||
/* Take the semaphore (perhaps waiting) */
|
||||
|
||||
while (sem_wait(&tree_sem) != 0)
|
||||
{
|
||||
/* The only case that an error should occr here is if
|
||||
* the wait was awakened by a signal.
|
||||
*/
|
||||
|
||||
ASSERT(*get_errno_ptr() == EINTR);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Name: inode_semgive
|
||||
************************************************************/
|
||||
|
||||
void inode_semgive(void)
|
||||
{
|
||||
sem_post(&tree_sem);
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Name: inode_search
|
||||
*
|
||||
* Description:
|
||||
* Find the inode associated with 'path' returning the
|
||||
* inode references and references to its companion nodes.
|
||||
*
|
||||
* Assumptions:
|
||||
* The caller holds the tree_sem
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
FAR struct inode *inode_search(const char **path,
|
||||
FAR struct inode **peer,
|
||||
FAR struct inode **parent)
|
||||
{
|
||||
const char *name = *path + 1; /* Skip over leading '/' */
|
||||
FAR struct inode *node = root_inode;
|
||||
@@ -237,7 +248,7 @@ static FAR struct inode *_inode_find(const char **path,
|
||||
* (2) the node we are looking for is "blow" this one.
|
||||
*/
|
||||
|
||||
name = _inode_nextname(name);
|
||||
name = inode_nextname(name);
|
||||
if (!*name)
|
||||
{
|
||||
/* We are at the end of the path, so this must be
|
||||
@@ -278,296 +289,32 @@ static FAR struct inode *_inode_find(const char **path,
|
||||
return node;
|
||||
}
|
||||
|
||||
static void _inode_insert(FAR struct inode *node,
|
||||
FAR struct inode *peer,
|
||||
FAR struct inode *parent)
|
||||
{
|
||||
/* If peer is non-null, then new node simply goes to the right
|
||||
* of that peer node.
|
||||
*/
|
||||
/************************************************************
|
||||
* Name: inode_free
|
||||
************************************************************/
|
||||
|
||||
if (peer)
|
||||
{
|
||||
node->i_peer = peer->i_peer;
|
||||
peer->i_peer = node;
|
||||
}
|
||||
|
||||
/* If parent is non-null, then it must go at the head of its
|
||||
* list of children.
|
||||
*/
|
||||
|
||||
else if (parent)
|
||||
{
|
||||
node->i_peer = parent->i_child;
|
||||
parent->i_child = node;
|
||||
}
|
||||
|
||||
/* Otherwise, this must be the new root_inode */
|
||||
|
||||
else
|
||||
{
|
||||
node->i_peer = root_inode;
|
||||
root_inode = node;
|
||||
}
|
||||
}
|
||||
|
||||
static void _inode_remove(struct inode *node,
|
||||
struct inode *peer,
|
||||
struct inode *parent)
|
||||
{
|
||||
/* If peer is non-null, then remove the node from the right of
|
||||
* of that peer node.
|
||||
*/
|
||||
|
||||
if (peer)
|
||||
{
|
||||
peer->i_peer = node->i_peer;
|
||||
}
|
||||
|
||||
/* If parent is non-null, then remove the node from head of
|
||||
* of the list of children.
|
||||
*/
|
||||
|
||||
else if (parent)
|
||||
{
|
||||
parent->i_child = node->i_peer;
|
||||
}
|
||||
|
||||
/* Otherwise, we must be removing the root inode. */
|
||||
|
||||
else
|
||||
{
|
||||
root_inode = node->i_peer;
|
||||
}
|
||||
node->i_peer = NULL;
|
||||
}
|
||||
|
||||
static void _inode_free(FAR struct inode *node)
|
||||
void inode_free(FAR struct inode *node)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
_inode_free(node->i_peer);
|
||||
_inode_free(node->i_child);
|
||||
inode_free(node->i_peer);
|
||||
inode_free(node->i_child);
|
||||
free(node);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************
|
||||
* Public Functions
|
||||
* Name: inode_nextname
|
||||
*
|
||||
* Description:
|
||||
* Given a path with node names separated by '/', return
|
||||
* the next node name.
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
/* This is called from the OS initialization logic to configure
|
||||
* the file system.
|
||||
*/
|
||||
|
||||
void fs_initialize(void)
|
||||
const char *inode_nextname(const char *name)
|
||||
{
|
||||
/* Initialize the semaphore to one (to support one-at-
|
||||
* a-time access to the inode tree).
|
||||
*/
|
||||
|
||||
(void)sem_init(&tree_sem, 0, 1);
|
||||
|
||||
/* Initialize files array (if it is used) */
|
||||
|
||||
#ifdef CONFIG_HAVE_WEAKFUNCTIONS
|
||||
if (files_initialize != NULL)
|
||||
#endif
|
||||
{
|
||||
files_initialize();
|
||||
}
|
||||
}
|
||||
|
||||
/* This is called from the open() logic to get a reference
|
||||
* to the inode associatged with a path.
|
||||
*/
|
||||
|
||||
FAR struct inode *inode_find(const char *path)
|
||||
{
|
||||
FAR struct inode *node;
|
||||
|
||||
if (!*path || path[0] != '/')
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find the node matching the path. If found,
|
||||
* increment the count of references on the node.
|
||||
*/
|
||||
|
||||
_inode_semtake();
|
||||
node = _inode_find(&path, (FAR void*)NULL, (FAR void*)NULL);
|
||||
if (node) node->i_crefs++;
|
||||
_inode_semgive();
|
||||
return node;
|
||||
}
|
||||
|
||||
/* Increment the reference count on an inode (as when a file
|
||||
* descriptor is dup'ed.
|
||||
*/
|
||||
|
||||
void inode_addref(FAR struct inode *inode)
|
||||
{
|
||||
if (inode)
|
||||
{
|
||||
_inode_semtake();
|
||||
inode->i_crefs++;
|
||||
_inode_semgive();
|
||||
}
|
||||
}
|
||||
|
||||
/* This is called from close() logic when it no longer refers
|
||||
* to the inode.
|
||||
*/
|
||||
|
||||
void inode_release(FAR struct inode *node)
|
||||
{
|
||||
if (node)
|
||||
{
|
||||
/* Decrement the references of the inode */
|
||||
|
||||
_inode_semtake();
|
||||
if (node->i_crefs)
|
||||
{
|
||||
node->i_crefs--;
|
||||
}
|
||||
|
||||
/* If the subtree was previously deleted and the reference
|
||||
* count has decrement to zero, then delete the inode
|
||||
* now.
|
||||
*/
|
||||
|
||||
if (node->i_crefs <= 0 && (node->i_flags & FSNODEFLAG_DELETED) != 0)
|
||||
{
|
||||
_inode_semgive();
|
||||
_inode_free(node->i_child);
|
||||
free(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
_inode_semgive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
STATUS register_inode(const char *path,
|
||||
struct file_operations *fops,
|
||||
mode_t mode, void *private)
|
||||
{
|
||||
const char *name = path;
|
||||
FAR struct inode *left;
|
||||
FAR struct inode *parent;
|
||||
|
||||
if (!*path || path[0] != '/')
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Find the location to insert the new subtree */
|
||||
|
||||
_inode_semtake();
|
||||
if (_inode_find(&name, &left, &parent) != NULL)
|
||||
{
|
||||
/* Is is an error if the node already exists in the tree */
|
||||
|
||||
_inode_semgive();
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Now we now where to insert the subtree */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
FAR struct inode *node;
|
||||
|
||||
/* Create a new node -- we need to know if this is the
|
||||
* the leaf node or some intermediary. We can find this
|
||||
* by looking at the next name.
|
||||
*/
|
||||
|
||||
const char *next_name = _inode_nextname(name);
|
||||
if (*next_name)
|
||||
{
|
||||
/* Insert an operationless node */
|
||||
|
||||
node = _inode_alloc(name, NULL, mode, NULL);
|
||||
if (node)
|
||||
{
|
||||
_inode_insert(node, left, parent);
|
||||
|
||||
/* Set up for the next time through the loop */
|
||||
|
||||
name = next_name;
|
||||
left = NULL;
|
||||
parent = node;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node = _inode_alloc(name, fops, mode, private);
|
||||
if (node)
|
||||
{
|
||||
_inode_insert(node, left, parent);
|
||||
_inode_semgive();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* We get here on failures to allocate node memory */
|
||||
|
||||
_inode_semgive();
|
||||
return ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
STATUS unregister_inode(const char *path)
|
||||
{
|
||||
const char *name = path;
|
||||
FAR struct inode *node;
|
||||
FAR struct inode *left;
|
||||
FAR struct inode *parent;
|
||||
|
||||
if (*path && path[0] == '/')
|
||||
{
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/* Find the node to delete */
|
||||
|
||||
_inode_semtake();
|
||||
node = _inode_find(&name, &left, &parent);
|
||||
if (node)
|
||||
{
|
||||
/* Found it, now remove it from the tree */
|
||||
|
||||
_inode_remove(node, left, parent);
|
||||
|
||||
/* We cannot delete it if there reference to the inode */
|
||||
|
||||
if (node->i_crefs)
|
||||
{
|
||||
/* In that case, we will mark it deleted, when the FS
|
||||
* releases the inode, we will then, finally delete
|
||||
* the subtree.
|
||||
*/
|
||||
|
||||
node->i_flags |= FSNODEFLAG_DELETED;
|
||||
_inode_semgive();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* And delete it now -- recursively to delete all of its children */
|
||||
|
||||
_inode_semgive();
|
||||
_inode_free(node->i_child);
|
||||
free(node);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
/* The node does not exist or it has references */
|
||||
_inode_semgive();
|
||||
return ERROR;
|
||||
while (*name && *name != '/') name++;
|
||||
if (*name) name++;
|
||||
return name;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user