diff --git a/ChangeLog b/ChangeLog
index 69437b88730..b8f92e7870a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -6609,5 +6609,8 @@
the kconfig-frontends tools (unverified) (2014-2-18).
* fs/fs_opendir.c, fs_readdir.c, et al: Modified so that errors
will not be reported if you attempt to list a empty pseudo-directory
- (2014-2-18).
+ (2014-2-19).
+ * fs/fs_rmdir.c: rmdir can be used to removed empty directories in
+ the pseudo-filesystem such as might be left after umounting a
+ file system (2014-2-19).
diff --git a/Documentation/NuttShell.html b/Documentation/NuttShell.html
index e3078d732c0..4130294cc42 100644
--- a/Documentation/NuttShell.html
+++ b/Documentation/NuttShell.html
@@ -8,7 +8,7 @@
NuttShell (NSH)
- Last Updated: February 3, 2014
+ Last Updated: February 19, 2014
|
@@ -2727,7 +2727,7 @@ nsh>
rmdir |
- !CONFIG_DISABLE_MOUNTPOINT && CONFIG_NFILE_DESCRIPTORS > 0 && CONFIG_FS_WRITABLE4 |
+ CONFIG_NFILE_DESCRIPTORS > 0 |
CONFIG_NSH_DISABLE_RMDIR |
diff --git a/fs/Makefile b/fs/Makefile
index 7e90c4f7e97..206d038a77e 100644
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -1,7 +1,7 @@
############################################################################
# fs/Makefile
#
-# Copyright (C) 2007, 2008, 2011-2013 Gregory Nutt. All rights reserved.
+# Copyright (C) 2007, 2008, 2011-2014 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt
#
# Redistribution and use in source and binary forms, with or without
@@ -35,10 +35,10 @@
-include $(TOPDIR)/Make.defs
-ASRCS =
-AOBJS = $(ASRCS:.S=$(OBJEXT))
+ASRCS =
+AOBJS = $(ASRCS:.S=$(OBJEXT))
-CSRCS =
+CSRCS =
# If there are no file descriptors configured, then a small part of the
# logic in this directory may still apply to socket descriptors
@@ -48,29 +48,30 @@ ifneq ($(CONFIG_NSOCKET_DESCRIPTORS),0)
# Socket descriptor support
-CSRCS += fs_close.c fs_read.c fs_write.c fs_ioctl.c fs_poll.c fs_select.c
+CSRCS += fs_close.c fs_read.c fs_write.c fs_ioctl.c fs_poll.c fs_select.c
endif
# Support for network access using streams
ifneq ($(CONFIG_NFILE_STREAMS),0)
-CSRCS += fs_fdopen.c
+CSRCS += fs_fdopen.c
endif
else
# Common file/socket descriptor support
-CSRCS += fs_close.c fs_closedir.c fs_dup.c fs_dup2.c fs_fcntl.c \
- fs_filedup.c fs_filedup2.c fs_ioctl.c fs_lseek.c fs_open.c \
- fs_opendir.c fs_poll.c fs_read.c fs_readdir.c fs_rewinddir.c \
- fs_seekdir.c fs_stat.c fs_statfs.c fs_select.c fs_write.c
-CSRCS += fs_files.c fs_foreachinode.c fs_inode.c fs_inodeaddref.c \
- fs_inodefind.c fs_inoderelease.c fs_inoderemove.c \
- fs_inodereserve.c
-CSRCS += fs_registerdriver.c fs_unregisterdriver.c
-CSRCS += fs_registerblockdriver.c fs_unregisterblockdriver.c \
- fs_findblockdriver.c fs_openblockdriver.c fs_closeblockdriver.c
+CSRCS += fs_close.c fs_closedir.c fs_dup.c fs_dup2.c fs_fcntl.c
+CSRCS += fs_filedup.c fs_filedup2.c fs_ioctl.c fs_lseek.c fs_open.c
+CSRCS += fs_opendir.c fs_poll.c fs_read.c fs_readdir.c fs_rewinddir.c
+CSRCS += fs_rmdir.c fs_seekdir.c fs_stat.c fs_statfs.c fs_select.c
+CSRCS += fs_write.c
+CSRCS += fs_files.c fs_foreachinode.c fs_inode.c fs_inodeaddref.c
+CSRCS += fs_inodefind.c fs_inoderelease.c fs_inoderemove.c
+CSRCS += fs_inodereserve.c
+CSRCS += fs_registerdriver.c fs_unregisterdriver.c
+CSRCS += fs_registerblockdriver.c fs_unregisterblockdriver.c
+CSRCS += fs_findblockdriver.c fs_openblockdriver.c fs_closeblockdriver.c
DEPPATH =
VPATH = .
@@ -80,7 +81,7 @@ include mmap/Make.defs
# Stream support
ifneq ($(CONFIG_NFILE_STREAMS),0)
-CSRCS += fs_fdopen.c
+CSRCS += fs_fdopen.c
endif
# Support for sendfile()
@@ -93,7 +94,7 @@ endif
ifeq ($(CONFIG_SYSLOG),y)
ifeq ($(CONFIG_SYSLOG_CHAR),y)
-CSRCS += fs_syslog.c
+CSRCS += fs_syslog.c
endif
endif
@@ -101,9 +102,9 @@ endif
ifneq ($(CONFIG_DISABLE_MOUNTPOINT),y)
-CSRCS += fs_fsync.c fs_mkdir.c fs_mount.c fs_rename.c fs_rmdir.c \
- fs_umount.c fs_unlink.c
-CSRCS += fs_foreachmountpoint.c
+CSRCS += fs_fsync.c fs_mkdir.c fs_mount.c fs_rename.c fs_umount.c
+CSRCS += fs_unlink.c
+CSRCS += fs_foreachmountpoint.c
include fat/Make.defs
include romfs/Make.defs
@@ -116,16 +117,16 @@ include procfs/Make.defs
endif
endif
-COBJS = $(CSRCS:.c=$(OBJEXT))
+COBJS = $(CSRCS:.c=$(OBJEXT))
-SRCS = $(ASRCS) $(CSRCS)
-OBJS = $(AOBJS) $(COBJS)
+SRCS = $(ASRCS) $(CSRCS)
+OBJS = $(AOBJS) $(COBJS)
-BIN = libfs$(LIBEXT)
+BIN = libfs$(LIBEXT)
-SUBDIRS = mmap fat romfs nxffs nfs binfs procfs
+SUBDIRS = mmap fat romfs nxffs nfs binfs procfs
-all: $(BIN)
+all: $(BIN)
$(AOBJS): %$(OBJEXT): %.S
$(call ASSEMBLE, $<, $@)
diff --git a/fs/fs_rmdir.c b/fs/fs_rmdir.c
index 317d7cc42e5..9c863d8c4fb 100644
--- a/fs/fs_rmdir.c
+++ b/fs/fs_rmdir.c
@@ -76,43 +76,85 @@ int rmdir(FAR const char *pathname)
{
FAR struct inode *inode;
const char *relpath = NULL;
- int ret;
+ int errcode;
- /* Get an inode for this file */
+ /* Get an inode for this file. inode_find() automatically increments the
+ * reference count on the inode if one is found.
+ */
inode = inode_find(pathname, &relpath);
if (!inode)
{
- /* There is no mountpoint that includes in this path */
+ /* There is no inode that includes in this path */
- ret = ENOENT;
+ errcode = ENOENT;
goto errout;
}
- /* Verify that the inode is a valid mountpoint. */
+#ifndef CONFIG_DISABLE_MOUNTPOINT
+ /* Check if the inode is a valid mountpoint. */
- if (!INODE_IS_MOUNTPT(inode) || !inode->u.i_mops)
+ if (INODE_IS_MOUNTPT(inode) && inode->u.i_mops)
{
- ret = ENXIO;
- goto errout_with_inode;
- }
+ /* Perform the rmdir operation using the relative path
+ * from the mountpoint.
+ */
- /* Perform the rmdir operation using the relative path
- * at the mountpoint.
+ if (inode->u.i_mops->rmdir)
+ {
+ int ret = inode->u.i_mops->rmdir(inode, relpath);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout_with_inode;
+ }
+ }
+ else
+ {
+ errcode = ENOSYS;
+ goto errout_with_inode;
+ }
+ }
+ else
+#endif
+
+ /* If this is a "dangling" pseudo-file node (i.e., it has no operations)
+ * then rmdir should remove the node.
*/
- if (inode->u.i_mops->rmdir)
+ if (!inode->u.i_ops)
{
- ret = inode->u.i_mops->rmdir(inode, relpath);
- if (ret < 0)
+ int ret;
+
+ /* If the directory inode has children, however, then it cannot be
+ * removed.
+ */
+
+ if (inode->i_child)
{
- ret = -ret;
+ errcode = ENOTEMPTY;
+ goto errout_with_inode;
+ }
+
+ /* Remove the inode. NOTE: Because we hold a reference count on the
+ * inode, it will not be deleted now. But probably when inode_release()
+ * is called below. inode_remove should return -EBUSY to indicate that
+ * the inode was not deleted now.
+ */
+
+ inode_semtake();
+ ret = inode_remove(pathname);
+ inode_semgive();
+
+ if (ret < 0 && ret != -EBUSY)
+ {
+ errcode = -ret;
goto errout_with_inode;
}
}
else
{
- ret = ENOSYS;
+ errcode = ENXIO;
goto errout_with_inode;
}
@@ -121,10 +163,10 @@ int rmdir(FAR const char *pathname)
inode_release(inode);
return OK;
- errout_with_inode:
+errout_with_inode:
inode_release(inode);
- errout:
- set_errno(ret);
+errout:
+ set_errno(errcode);
return ERROR;
}