summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cpukit/ChangeLog52
-rw-r--r--cpukit/Makefile.am23
-rw-r--r--cpukit/libblock/src/flashdisk.c14
-rw-r--r--cpukit/libblock/src/nvdisk.c6
-rw-r--r--cpukit/libblock/src/ramdisk-driver.c2
-rw-r--r--cpukit/libfs/Makefile.am15
-rw-r--r--cpukit/libfs/README24
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-bitmaps-ut.c389
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-bitmaps.c642
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-bitmaps.h305
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-block-pos.h233
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-block.c800
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-block.h302
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-buffer-bdbuf.c87
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-buffer-devio.c57
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-buffer.c478
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-buffer.h262
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-data.h78
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-dir-hash.c337
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-dir-hash.h34
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-dir.c742
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-dir.h206
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-file-system-fwd.h27
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-file-system.c278
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-file-system.h383
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-file.c573
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-file.h393
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-format.c627
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-format.h90
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-group.c316
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-group.h151
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-inode.c370
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-inode.h688
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-link.c439
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-link.h99
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-mutex.c68
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-mutex.h108
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems-dev.c271
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c238
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems-file.c334
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems-utils.c240
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems.c1235
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-rtems.h318
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-shell.c666
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-shell.h35
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-trace.c154
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs-trace.h126
-rw-r--r--cpukit/libfs/src/rfs/rtems-rfs.h35
-rw-r--r--cpukit/libmisc/shell/main_ls.c5
-rw-r--r--cpukit/libmisc/shell/print-ls.c7
-rw-r--r--cpukit/libnetworking/nfs/bootp_subr.c78
-rw-r--r--cpukit/libnetworking/rtems/rtems_bootp.c10
-rw-r--r--cpukit/libnetworking/rtems/rtems_bsdnet_internal.h2
-rw-r--r--cpukit/preinstall.am77
-rw-r--r--cpukit/wrapup/Makefile.am1
55 files changed, 13476 insertions, 54 deletions
diff --git a/cpukit/ChangeLog b/cpukit/ChangeLog
index 5f1856004c..db91adf397 100644
--- a/cpukit/ChangeLog
+++ b/cpukit/ChangeLog
@@ -1,3 +1,55 @@
+2010-02-18 Chris Johns <chrisj@rtems.org>
+
+ * libfs/src/rfs/rtems-rfs-bitmaps.c,
+ libfs/src/rfs/rtems-rfs-bitmaps.h,
+ libfs/src/rfs/rtems-rfs-bitmaps-ut.c,
+ libfs/src/rfs/rtems-rfs-block.c, libfs/src/rfs/rtems-rfs-block.h,
+ libfs/src/rfs/rtems-rfs-block-pos.h,
+ libfs/src/rfs/rtems-rfs-buffer-bdbuf.c,
+ libfs/src/rfs/rtems-rfs-buffer.c,
+ libfs/src/rfs/rtems-rfs-buffer-devio.c,
+ libfs/src/rfs/rtems-rfs-buffer.h, libfs/src/rfs/rtems-rfs-data.h,
+ libfs/src/rfs/rtems-rfs-dir.c, libfs/src/rfs/rtems-rfs-dir.h,
+ libfs/src/rfs/rtems-rfs-dir-hash.c,
+ libfs/src/rfs/rtems-rfs-dir-hash.h,
+ libfs/src/rfs/rtems-rfs-file.c, libfs/src/rfs/rtems-rfs-file.h,
+ libfs/src/rfs/rtems-rfs-file-system.c,
+ libfs/src/rfs/rtems-rfs-file-system-fwd.h,
+ libfs/src/rfs/rtems-rfs-file-system.h,
+ libfs/src/rfs/rtems-rfs-format.c,
+ libfs/src/rfs/rtems-rfs-format.h, libfs/src/rfs/rtems-rfs-group.c,
+ libfs/src/rfs/rtems-rfs-group.h, libfs/src/rfs/rtems-rfs.h,
+ libfs/src/rfs/rtems-rfs-inode.c, libfs/src/rfs/rtems-rfs-inode.h,
+ libfs/src/rfs/rtems-rfs-link.c, libfs/src/rfs/rtems-rfs-link.h,
+ libfs/src/rfs/rtems-rfs-mutex.c, libfs/src/rfs/rtems-rfs-mutex.h,
+ libfs/src/rfs/rtems-rfs-rtems.c,
+ libfs/src/rfs/rtems-rfs-rtems-dev.c,
+ libfs/src/rfs/rtems-rfs-rtems-dir.c,
+ libfs/src/rfs/rtems-rfs-rtems-file.c,
+ libfs/src/rfs/rtems-rfs-rtems.h,
+ libfs/src/rfs/rtems-rfs-rtems-utils.c,
+ libfs/src/rfs/rtems-rfs-shell.c, libfs/src/rfs/rtems-rfs-shell.h,
+ libfs/src/rfs/rtems-rfs-trace.c, libfs/src/rfs/rtems-rfs-trace.h:
+ New.
+
+ * Makefile.am, preinstall.am, libfs/Makefile.am,
+ wrapup/Makefile.am: Updated with the RFS support.
+
+ * libfs/README: Updated after 10 years.
+
+ * libblock/src/flashdisk.c, libblock/src/nvdisk.c,
+ libblock/src/ramdisk-driver.c: Updated to the new error reporting
+ in libblock.
+
+ * libmisc/shell/main_ls.c, libmisc/shell/print-ls.c: Fix printing
+ the size in long mode.
+
+ * libnetworking/nfs/bootp_subr.c,
+ libnetworking/rtems/rtems_bootp.c,
+ libnetworking/rtems/rtems_bsdnet_internal.h: Return the BOOTP/DHCP
+ to the forever behaviour of 4.9 with the ability to call BOOTP and
+ control the process if required.
+
2010-02-16 Chris Johns <chrisj@rtems.org>
* libcsupport/src/open.c: Tighten the open handler check.
diff --git a/cpukit/Makefile.am b/cpukit/Makefile.am
index 4a0885fd6b..11df9c0c93 100644
--- a/cpukit/Makefile.am
+++ b/cpukit/Makefile.am
@@ -95,6 +95,29 @@ if LIBDOSFS
include_rtems_HEADERS += libfs/src/dosfs/dosfs.h
endif
+# RFS
+include_rtems_HEADERS += \
+ libfs/src/rfs/rtems-rfs.h \
+ libfs/src/rfs/rtems-rfs-format.h \
+ libfs/src/rfs/rtems-rfs-shell.h
+include_rtems_rfsdir = $(include_rtemsdir)/rfs
+include_rtems_rfs_HEADERS = \
+ libfs/src/rfs/rtems-rfs-bitmaps.h \
+ libfs/src/rfs/rtems-rfs-block-pos.h \
+ libfs/src/rfs/rtems-rfs-block.h \
+ libfs/src/rfs/rtems-rfs-buffer.h \
+ libfs/src/rfs/rtems-rfs-data.h \
+ libfs/src/rfs/rtems-rfs-dir.h \
+ libfs/src/rfs/rtems-rfs-dir-hash.h \
+ libfs/src/rfs/rtems-rfs-file.h \
+ libfs/src/rfs/rtems-rfs-file-system-fwd.h \
+ libfs/src/rfs/rtems-rfs-file-system.h \
+ libfs/src/rfs/rtems-rfs-group.h \
+ libfs/src/rfs/rtems-rfs-inode.h \
+ libfs/src/rfs/rtems-rfs-link.h \
+ libfs/src/rfs/rtems-rfs-mutex.h \
+ libfs/src/rfs/rtems-rfs-trace.h
+
## libblock
include_rtems_HEADERS += libblock/include/rtems/bdbuf.h \
libblock/include/rtems/blkdev.h libblock/include/rtems/diskdevs.h \
diff --git a/cpukit/libblock/src/flashdisk.c b/cpukit/libblock/src/flashdisk.c
index a1c8ea5036..322e21c0b7 100644
--- a/cpukit/libblock/src/flashdisk.c
+++ b/cpukit/libblock/src/flashdisk.c
@@ -134,7 +134,7 @@
* @todo A sequence number for the block could be added. This would
* mean a larger descriptor size. Need to make the sequence
* large like 20+ bits so a large file system would not have
- * more blocks available then the sequence number.
+ * more blocks available than the sequence number.
*/
typedef struct rtems_fdisk_page_desc
{
@@ -1304,9 +1304,9 @@ rtems_fdisk_queue_segment (rtems_flashdisk* fd, rtems_fdisk_segment_ctl* sc)
/**
* Compact the used segments to free what is available. Find the segment
- * with the most avalable number of pages and see if the we have
+ * with the most avalable number of pages and see if we have
* used segments that will fit. The used queue is sorted on the least
- * number active pages.
+ * number of active pages.
*/
static int
rtems_fdisk_compact (rtems_flashdisk* fd)
@@ -1701,7 +1701,7 @@ rtems_fdisk_recover_block_mappings (rtems_flashdisk* fd)
* @return EIO Invalid block size, block number, segment pointer, crc,
* page flags.
*/
-static int
+static bool
rtems_fdisk_read_block (rtems_flashdisk* fd,
uint32_t block,
uint8_t* buffer)
@@ -2071,7 +2071,8 @@ rtems_fdisk_read (rtems_flashdisk* fd, rtems_blkdev_request* req)
}
}
- req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR);
+ req->status = ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL;
+ req->req_done (req->done_arg, req->status);
return ret;
}
@@ -2106,7 +2107,8 @@ rtems_fdisk_write (rtems_flashdisk* fd, rtems_blkdev_request* req)
}
}
- req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR);
+ req->status = ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL;
+ req->req_done (req->done_arg, req->status);
return 0;
}
diff --git a/cpukit/libblock/src/nvdisk.c b/cpukit/libblock/src/nvdisk.c
index fde4a025d9..0d41b6e803 100644
--- a/cpukit/libblock/src/nvdisk.c
+++ b/cpukit/libblock/src/nvdisk.c
@@ -595,7 +595,8 @@ rtems_nvdisk_read (rtems_nvdisk* nvd, rtems_blkdev_request* req)
}
}
- req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR);
+ req->status = ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL;
+ req->req_done (req->done_arg, req->status);
return ret;
}
@@ -634,7 +635,8 @@ rtems_nvdisk_write (rtems_nvdisk* nvd, rtems_blkdev_request* req)
}
}
- req->req_done (req->done_arg, ret ? RTEMS_SUCCESSFUL : RTEMS_IO_ERROR);
+ req->status = ret ? RTEMS_IO_ERROR : RTEMS_SUCCESSFUL;
+ req->req_done (req->done_arg, req->status);
return 0;
}
diff --git a/cpukit/libblock/src/ramdisk-driver.c b/cpukit/libblock/src/ramdisk-driver.c
index 1e078fdf2a..ce3b444da2 100644
--- a/cpukit/libblock/src/ramdisk-driver.c
+++ b/cpukit/libblock/src/ramdisk-driver.c
@@ -65,6 +65,7 @@ ramdisk_read(struct ramdisk *rd, rtems_blkdev_request *req)
#endif
memcpy(sg->buffer, from + (sg->block * rd->block_size), sg->length);
}
+ req->status = RTEMS_SUCCESSFUL;
req->req_done(req->done_arg, RTEMS_SUCCESSFUL);
return 0;
}
@@ -89,6 +90,7 @@ ramdisk_write(struct ramdisk *rd, rtems_blkdev_request *req)
#endif
memcpy(to + (sg->block * rd->block_size), sg->buffer, sg->length);
}
+ req->status = RTEMS_SUCCESSFUL;
req->req_done(req->done_arg, RTEMS_SUCCESSFUL);
return 0;
}
diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am
index 6eb3ead8e2..56cdaa0052 100644
--- a/cpukit/libfs/Makefile.am
+++ b/cpukit/libfs/Makefile.am
@@ -62,6 +62,21 @@ libdosfs_a_SOURCES += src/dosfs/msdos_create.c src/dosfs/msdos_dir.c \
src/dosfs/dosfs.h
endif
+# RFS
+noinst_LIBRARIES += librfs.a
+librfs_a_SOURCES = \
+ src/rfs/rtems-rfs-bitmaps.c src/rfs/rtems-rfs-block.c \
+ src/rfs/rtems-rfs-buffer-bdbuf.c src/rfs/rtems-rfs-buffer.c \
+ src/rfs/rtems-rfs-dir-hash.c src/rfs/rtems-rfs-file.c \
+ src/rfs/rtems-rfs-group.c src/rfs/rtems-rfs-inode.c \
+ src/rfs/rtems-rfs-rtems-dev.c src/rfs/rtems-rfs-rtems-utils.c \
+ src/rfs/rtems-rfs-rtems.c src/rfs/rtems-rfs-shell.c \
+ src/rfs/rtems-rfs-bitmaps-ut.c src/rfs/rtems-rfs-dir.c \
+ src/rfs/rtems-rfs-file-system.c src/rfs/rtems-rfs-format.c \
+ src/rfs/rtems-rfs-link.c src/rfs/rtems-rfs-mutex.c \
+ src/rfs/rtems-rfs-rtems-dir.c src/rfs/rtems-rfs-rtems-file.c \
+ src/rfs/rtems-rfs-trace.c
+
# ---
include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/local.am
diff --git a/cpukit/libfs/README b/cpukit/libfs/README
index 7409b93dca..dfd7682099 100644
--- a/cpukit/libfs/README
+++ b/cpukit/libfs/README
@@ -5,9 +5,25 @@
This directory contains for the "file system" library. All supported
file systems live under this tree.
-Currently the only supported file systems in this library are the IMFS
-and miniIMFS. The TFTP client filesystem is part of the libnetworking
-library.
+Currently the supported file systems in this library are:
+
+- IMFS or In Memory File System
+
+ This is the only root file system on RTEMS at the moment. It supports
+ files, directories, device nodes and mount points. It can also be
+ configured to be the miniIMFS.
+
+- TFTP and FTP filesystem are part of the libnetworking library.
+
+- DEVFS or Device File system
+
+- DOSFS, a FAT 12/16/32 MSDOS compatible file system.
+
+- NFS Client, can mount NFS exported file systems.
+
+- PIPE, a pipe file system.
+
+- RFS, The RTEMS File System.
--Chris Johns and Joel Sherrill
-18 October 2000
+ 17 Feb 2010
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-bitmaps-ut.c b/cpukit/libfs/src/rfs/rtems-rfs-bitmaps-ut.c
new file mode 100644
index 0000000000..ad571af1bb
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-bitmaps-ut.c
@@ -0,0 +1,389 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Bitmap Unit Test..
+ *
+ * This is a unit test module for the bit map functions.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <rtems/rfs/rtems-rfs-bitmaps.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+
+#define rtems_rfs_exit_on_error(_rc, _r, _c, _b) \
+ if ((_rc > 0) || _r) { free (_b); rtems_rfs_bitmap_close (_c); return; }
+
+static bool
+rtems_rfs_bitmap_ut_test_range (rtems_rfs_bitmap_control* control,
+ int test,
+ bool set,
+ rtems_rfs_bitmap_bit bit,
+ size_t size)
+{
+ unsigned int count;
+ bool result;
+ for (count = 0; count < size; count++)
+ {
+ int rc = rtems_rfs_bitmap_map_test (control, bit + count, &result);
+ if (rc > 0)
+ {
+ printf (" %2d. Test bit %ld in range (%ld,%ld] is %s: ",
+ test, bit + count, bit, bit + size - 1, !set ? "set" : "clear");
+ printf ("FAIL (%s)\n", strerror (rc));
+ return false;
+ }
+ if (!set)
+ result = !result;
+ if (!result)
+ {
+ printf (" %2d. Test bit %ld in range (%ld,%ld] is %s: ",
+ test, bit + count, bit, bit + size - 1, !set ? "set" : "clear");
+ printf (" %s\n", !result ? "pass" : "FAIL");
+ return false;
+ }
+ }
+
+ printf (" %2d. Test bit range (%ld,%ld] all %s: pass\n",
+ test, bit, bit + size - 1, set ? "set" : "clear");
+
+ return true;
+}
+
+static bool
+rtems_rfs_bitmap_ut_alloc_seq_test (rtems_rfs_bitmap_control* control,
+ int test,
+ rtems_rfs_bitmap_bit bit,
+ size_t size)
+{
+ bool state;
+ int i;
+ int rc;
+
+ printf (" %2d. Set all bits\n", test);
+ rc = rtems_rfs_bitmap_map_set_all (control);
+ if (rc > 0)
+ {
+ printf (" %2d. set all bits: FAIL (%s)\n", test, strerror (rc));
+ return false;
+ }
+
+ for (i = 0; i < size; i++)
+ rtems_rfs_bitmap_map_clear (control, bit + i);
+
+ printf (" %2d. Cleared bits (%ld, %ld] (%ld)\n",
+ test, bit, bit + size - 1, size);
+
+ for (i = 0; i < rtems_rfs_bitmap_element_bits (); i++)
+ {
+ rc = rtems_rfs_bitmap_map_test (control, bit + i, &state);
+ if (rc > 0)
+ {
+ printf (" %2d. test bit: FAIL (%s)\n", test, strerror (rc));
+ return false;
+ }
+ if (state)
+ {
+ printf (" %2d. Cleared bit still set: bit = %ld\n", test, bit + i);
+ return false;
+ }
+ }
+
+ for (i = 0, bit = 0; i < size; i++)
+ {
+ rtems_rfs_bitmap_bit seed = bit;
+ bool result;
+ int rc;
+ rc = rtems_rfs_bitmap_map_alloc (control, seed, &result, &bit);
+ if (rc > 0)
+ {
+ printf (" %2d. map all: FAIL (%s)\n", test, strerror (rc));
+ return false;
+ }
+ if (!result)
+ {
+ printf (" %2d. Find bit with seed = %ld: %s: bit = %ld\n",
+ test, seed, result ? "pass" : "FAIL", bit);
+ return false;
+ }
+ }
+
+ printf (" %2d. Alloc'ed all bits (%ld, %ld] (%ld)\n",
+ test, bit, bit + size - 1, size);
+
+ return true;
+}
+
+static void
+rtems_rfs_bitmap_ut_test_bitmap (size_t size)
+{
+ rtems_rfs_file_system fs;
+ rtems_rfs_bitmap_control control;
+ rtems_rfs_buffer_handle handle;
+ rtems_rfs_buffer buffer;
+ rtems_rfs_bitmap_bit bit = 0;
+ rtems_rfs_bitmap_bit first_bit;
+ rtems_rfs_bitmap_bit last_bit;
+ bool result;
+ size_t bytes;
+ size_t clear;
+ int rc;
+
+ bytes = (rtems_rfs_bitmap_elements (size) *
+ sizeof (rtems_rfs_bitmap_element));
+
+ memset (&fs, 0, sizeof (fs));
+ memset (&buffer, 0, sizeof (buffer));
+
+ buffer.buffer = malloc (bytes);
+ buffer.block = 1;
+
+ if (!buffer.buffer)
+ {
+ printf (" Cannot allocate bitmap memory\n");
+ return;
+ }
+
+#if RTEMS_RFS_BITMAP_CLEAR_ZERO
+ memset (buffer.buffer, 0, bytes);
+#else
+ memset (buffer.buffer, 0xff, bytes);
+#endif
+
+ /*
+ * Do not close the handle so no writes need occur.
+ */
+ rc = rtems_rfs_buffer_handle_open (&fs, &handle);
+ if (rc > 0)
+ {
+ printf (" Cannot open the handle: %d: %s\n", rc, strerror (rc));
+ free (buffer.buffer);
+ return;
+ }
+
+ handle.buffer = &buffer;
+ handle.bnum = 1;
+
+ printf ("\nRFS Bitmap Test : size = %ld (%ld)\n",
+ size, rtems_rfs_bitmap_elements (size));
+ rc = rtems_rfs_bitmap_open (&control, &fs, &handle, size, 1);
+ if (rc > 0)
+ {
+ printf (" Cannot open the bitmap: %s\n", strerror (rc));
+ free (buffer.buffer);
+ return;
+ }
+
+ /*
+ * This is a new bitmap with no bits set. Try and find a bit with a few
+ * seeds.
+ */
+ rc = rtems_rfs_bitmap_map_alloc (&control, size * 2, &result, &bit);
+ printf (" 1. Find bit with seed > size: %s (%s)\n",
+ result ? "FAIL" : "pass", strerror (rc));
+ rtems_rfs_exit_on_error (rc, result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, size, &result, &bit);
+ printf (" 2. Find bit with seed = size: %s (%s)\n",
+ result ? "FAIL" : "pass", strerror (rc));
+ rtems_rfs_exit_on_error (rc, result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, 0, &result, &bit);
+ result = result && (bit == 0);
+ printf (" 3. Find bit 0 with seed = 0: %s (%s): bit = %ld\n",
+ result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, size - 1, &result, &bit);
+ result = result && (bit == (size - 1));
+ printf (" 4. Find bit (size - 1) with seed = (size - 1) (%ld): %s (%s): bit = %ld\n",
+ size - 1, result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+
+ /*
+ * Test the bits allocated to make sure they are set.
+ */
+
+ rc = rtems_rfs_bitmap_map_test (&control, 0, &result);
+ printf (" 5. Test bit 0: %s (%s)\n",
+ result ? "pass" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_test (&control, size - 1, &result);
+ printf (" 6. Test bit (size - 1) (%ld): %s (%s)\n",
+ size - 1, result ? "pass" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ if (!rtems_rfs_bitmap_ut_test_range (&control, 7, false, 1, size - 2))
+ rtems_rfs_exit_on_error (0, !result, &control, buffer.buffer);
+
+ /*
+ * Set all bits then clear one and find it.
+ */
+ rc = rtems_rfs_bitmap_map_set_all (&control);
+ printf (" 8. Set all bits: %s (%s)\n",
+ rc == 0 ? "PASS" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+
+ bit = rand () % size;
+
+ rc = rtems_rfs_bitmap_map_clear (&control, bit);
+ printf (" 9. Clear bit %ld: %s (%s)\n",
+ bit, rc == 0 ? "PASS" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+
+ last_bit = bit;
+ rc = rtems_rfs_bitmap_map_alloc (&control, 0, &result, &bit);
+ result = result && (bit == last_bit);
+ printf (" 10. Find bit with seed = 0: %s (%s): bit = %ld\n",
+ result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, 0, &result, &bit);
+ result = !result || (bit != last_bit);
+ printf (" 11. Fail to find bit with seed = 0: %s (%s): bit = %ld\n",
+ result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_clear (&control, 0);
+ printf (" 12. Clear bit 0: %s (%s)\n",
+ rc == 0 ? "pass" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, size - 1, &result, &bit);
+ result = result && (bit == 0);
+ printf (" 13. Find bit with seed = (size - 1): %s (%s): bit = %ld\n",
+ result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_clear (&control, size - 1);
+ printf (" 14. Clear bit (size - 1) (%ld): %s (%s)\n",
+ size - 1, rc == 0 ? "pass" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, 0, &result, &bit);
+ result = result && (bit == (size - 1));
+ printf (" 15. Find bit with seed = 0: %s (%s): bit = %ld\n",
+ result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_clear (&control, 0);
+ printf (" 16. Clear bit 0: %s (%s)\n",
+ rc == 0 ? "pass" : "FAIL", strerror (rc));
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, size / 2, &result, &bit);
+ result = result && (bit == 0);
+ printf (" 17. Find bit with seed = (size / 2) (%ld): %s (%s): bit = %ld\n",
+ size / 2, result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_clear (&control, size - 1);
+ printf (" 18. Clear bit (size - 1) (%ld): %s, (%s)\n",
+ size - 1, rc == 0 ? "pass" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, size / 2, &result, &bit);
+ result = result && (bit == (size - 1));
+ printf (" 19. Find bit with seed = (size / 2) (%ld): %s (%s): bit = %ld\n",
+ size / 2, result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_clear (&control, 0);
+ printf (" 20. Clear bit 0: %s (%s)\n",
+ rc == 0 ? "pass" : "FAIL", strerror (rc));
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, (size / 2) - 1, &result, &bit);
+ result = result && (bit == 0);
+ printf (" 21. Find bit with seed = ((size / 2) - 1) (%ld): %s (%s): bit = %ld\n",
+ (size / 2) - 1, result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rc = rtems_rfs_bitmap_map_clear (&control, size - 1);
+ printf (" 22. Clear bit (size - 1) (%ld): %s (%s)\n",
+ size - 1, rc == 0 ? "pass" : "FAIL", strerror (rc));
+
+ rc = rtems_rfs_bitmap_map_alloc (&control, (size / 2) - 1, &result, &bit);
+ result = result && (bit == (size - 1));
+ printf (" 23. Find bit with seed = ((size / 2) - 1) (%ld): %s (%s): bit = %ld\n",
+ (size / 2) - 1, result ? "pass" : "FAIL", strerror (rc), bit);
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ bit = rand () % (size / 2) + rtems_rfs_bitmap_element_bits ();
+ result = rtems_rfs_bitmap_ut_alloc_seq_test (&control, 23, bit,
+ rtems_rfs_bitmap_element_bits ());
+ rtems_rfs_exit_on_error (0, !result, &control, buffer.buffer);
+
+ bit = rand () % (size / 2) + rtems_rfs_bitmap_element_bits ();
+ result = rtems_rfs_bitmap_ut_alloc_seq_test (&control, 24, bit, 57);
+ rtems_rfs_exit_on_error (0, !result, &control, buffer.buffer);
+
+ /*
+ * Set all bits, clear a random numberone then create a search map and make
+ * sure the clear count is correct.
+ */
+ rc = rtems_rfs_bitmap_map_set_all (&control);
+ printf (" 25. Set all bits: %s (%s)\n",
+ rc == 0 ? "PASS" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+
+ first_bit = rand () % (size / 2) + rtems_rfs_bitmap_element_bits ();
+ last_bit = first_bit + rand () % (size / 2) + rtems_rfs_bitmap_element_bits ();
+
+ for (bit = first_bit; bit < last_bit; bit++)
+ {
+ rc = rtems_rfs_bitmap_map_clear (&control, bit);
+ if (rc > 0)
+ {
+ printf (" 26. Clear bit %ld: %s (%s)\n",
+ bit, rc == 0 ? "PASS" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, false, &control, buffer.buffer);
+ }
+ }
+
+ printf (" 26. Clear bit (%ld, %ld]: %s (%s)\n",
+ first_bit, last_bit, rc == 0 ? "PASS" : "FAIL", strerror (rc));
+
+ clear = rtems_rfs_bitmap_map_free (&control);
+ result = clear == (last_bit - first_bit);
+ printf (" 27. Check free count is %ld: %ld: %s (%s)\n",
+ clear, last_bit - first_bit,
+ result ? "pass" : "FAIL", strerror (rc));
+
+ rc = rtems_rfs_bitmap_create_search (&control);
+ result = clear == rtems_rfs_bitmap_map_free (&control);
+ printf (" 28. Create search check free count is %ld: %ld: %s (%s)\n",
+ clear, rtems_rfs_bitmap_map_free (&control),
+ result ? "pass" : "FAIL", strerror (rc));
+ rtems_rfs_exit_on_error (rc, !result, &control, buffer.buffer);
+
+ rtems_rfs_bitmap_close (&control);
+ free (buffer.buffer);
+}
+
+void
+rtems_rfs_bitmap_unit_test (void)
+{
+ printf ("RTEMS File System Bitmap Unit Test\n");
+ printf (" Bit set value : %d\n", RTEMS_RFS_BITMAP_BIT_SET);
+ printf (" Bit clear value : %d\n", RTEMS_RFS_BITMAP_BIT_CLEAR);
+ printf (" Num bit per element : %ld\n", rtems_rfs_bitmap_element_bits ());
+
+ srand (0x23984237);
+
+ rtems_rfs_bitmap_ut_test_bitmap (2048);
+ rtems_rfs_bitmap_ut_test_bitmap (420);
+}
+
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.c b/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.c
new file mode 100644
index 0000000000..4de86342b0
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.c
@@ -0,0 +1,642 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Bitmap Routines.
+ *
+ * These functions manage bit maps. A bit map consists of the map of bit
+ * allocated in a block and a search map where a bit represents 32 actual
+ * bits. The search map allows for a faster search for an available bit as 32
+ * search bits can checked in a test.
+ */
+
+/**
+ * Set to 1 to enable warnings when developing.
+ */
+#define RTEMS_RFS_BITMAP_WARNINGS 0
+
+#if RTEMS_RFS_BITMAP_WARNINGS
+#include <stdio.h>
+#endif
+#include <stdlib.h>
+#include <rtems/rfs/rtems-rfs-bitmaps.h>
+
+/**
+ * Test a bit in an element. If set return true else return false.
+ *
+ * @param target The target to test the bit in.
+ * @param bit The bit to test.
+ * @retval true The bit is set.
+ * @retval false The bit is clear.
+ */
+static bool
+rtems_rfs_bitmap_test (rtems_rfs_bitmap_element target,
+ rtems_rfs_bitmap_bit bit)
+{
+ return RTEMS_RFS_BITMAP_TEST_BIT (target, bit);
+}
+
+/**
+ * Set the bits in the element. Bits not set in the bit argument are left
+ * unchanged.
+ *
+ * @param target The target element bits are set.
+ * @param bits The bits in the target to set. A 1 in the bits will set the
+ * same bit in the target.
+ */
+static rtems_rfs_bitmap_element
+rtems_rfs_bitmap_set (rtems_rfs_bitmap_element target,
+ rtems_rfs_bitmap_element bits)
+{
+ return RTEMS_RFS_BITMAP_SET_BITS (target, bits);
+}
+
+/**
+ * Clear the bits in the element. Bits not set in the bit argument are left
+ * unchanged.
+ *
+ * @param target The target element to clear the bits in.
+ * @param bits The bits in the target to clear. A 1 in the bits will clear the
+ * bit in the target.
+ */
+static rtems_rfs_bitmap_element
+rtems_rfs_bitmap_clear (rtems_rfs_bitmap_element target,
+ rtems_rfs_bitmap_element bits)
+{
+ return RTEMS_RFS_BITMAP_CLEAR_BITS (target, bits);
+}
+
+/**
+ * Merge the bits in 2 variables based on the mask. A set bit in the mask will
+ * merge the bits from bits1 and a clear bit will merge the bits from bits2.
+ * The mask is always defined as 1 being set and 0 being clear.
+ */
+static rtems_rfs_bitmap_element
+rtems_rfs_bitmap_merge (rtems_rfs_bitmap_element bits1,
+ rtems_rfs_bitmap_element bits2,
+ rtems_rfs_bitmap_element mask)
+{
+ /*
+ * Use the normal bit operators because we do not change the bits just merge
+ * the 2 separate parts.
+ */
+ bits1 &= mask;
+ bits2 &= RTEMS_RFS_BITMAP_INVERT_MASK (mask);
+ return bits1 | bits2;
+}
+
+/**
+ * Match the bits of 2 elements and return true if they match else return
+ * false.
+ *
+ * @param bits1 One set of bits to match.
+ * @param bits2 The second set of bits to match.
+ * @retval true The bits match.
+ * @retval false The bits do not match.
+ */
+static bool
+rtems_rfs_bitmap_match (rtems_rfs_bitmap_element bits1,
+ rtems_rfs_bitmap_element bits2)
+{
+ return bits1 ^ bits2 ? false : true;
+}
+
+#if RTEMS_NOT_USED_BUT_KEPT
+/**
+ * Match the bits of 2 elements within the mask and return true if they match
+ * else return false.
+ *
+ * @param mask The mask over which the match occurs. A 1 is a valid mask bit.
+ * @param bits1 One set of bits to match.
+ * @param bits2 The second set of bits to match.
+ * @retval true The bits match.
+ * @retval false The bits do not match.
+ */
+static bool
+rtems_rfs_bitmap_match_masked (rtems_rfs_bitmap_element mask,
+ rtems_rfs_bitmap_element bits1,
+ rtems_rfs_bitmap_element bits2)
+{
+ return (bits1 ^ bits2) & mask ? false : true;
+}
+#endif
+
+/**
+ * Return the map after loading from disk if not already loaded.
+ *
+ * @param control The bitmap control.
+ * @param rtems_rfs_bitmap_map* Pointer to the bitmap map data if no error.
+ * @return int The error number (errno). No error if 0.
+ */
+static int
+rtems_rfs_bitmap_load_map (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_map* map)
+{
+ int rc;
+
+ if (!control->buffer)
+ return ENXIO;
+
+ *map = NULL;
+
+ rc = rtems_rfs_buffer_handle_request (control->fs,
+ control->buffer,
+ control->block,
+ true);
+ if (rc)
+ return rc;
+
+ *map = rtems_rfs_buffer_data (control->buffer);
+ return 0;
+}
+
+rtems_rfs_bitmap_element
+rtems_rfs_bitmap_mask (unsigned int size)
+{
+ rtems_rfs_bitmap_element mask = RTEMS_RFS_BITMAP_ELEMENT_FULL_MASK;
+ mask >>= (rtems_rfs_bitmap_element_bits () - size);
+ return mask;
+}
+
+rtems_rfs_bitmap_element
+rtems_rfs_bitmap_mask_section (unsigned int start, unsigned int end)
+{
+ rtems_rfs_bitmap_element mask = 0;
+ if (end > start)
+ mask = rtems_rfs_bitmap_mask (end - start) << start;
+ return mask;
+}
+
+int
+rtems_rfs_bitmap_map_set (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit bit)
+{
+ rtems_rfs_bitmap_map map;
+ rtems_rfs_bitmap_map search_map;
+ int index;
+ int offset;
+ int rc;
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+ if (bit >= control->size)
+ return EINVAL;
+ search_map = control->search_bits;
+ index = rtems_rfs_bitmap_map_index (bit);
+ offset = rtems_rfs_bitmap_map_offset (bit);
+ map[index] = rtems_rfs_bitmap_set (map[index], 1 << offset);
+ if (rtems_rfs_bitmap_match(map[index], RTEMS_RFS_BITMAP_ELEMENT_SET))
+ {
+ bit = index;
+ index = rtems_rfs_bitmap_map_index (bit);
+ offset = rtems_rfs_bitmap_map_offset (bit);
+ search_map[index] = rtems_rfs_bitmap_set (search_map[index], 1 << offset);
+ control->free--;
+ rtems_rfs_buffer_mark_dirty (control->buffer);
+ }
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_map_clear (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit bit)
+{
+ rtems_rfs_bitmap_map map;
+ rtems_rfs_bitmap_map search_map;
+ int index;
+ int offset;
+ int rc;
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+ if (bit >= control->size)
+ return EINVAL;
+ search_map = control->search_bits;
+ index = rtems_rfs_bitmap_map_index (bit);
+ offset = rtems_rfs_bitmap_map_offset (bit);
+ map[index] = rtems_rfs_bitmap_clear (map[index], 1 << offset);
+ bit = index;
+ index = rtems_rfs_bitmap_map_index (bit);
+ offset = rtems_rfs_bitmap_map_offset(bit);
+ search_map[index] = rtems_rfs_bitmap_clear (search_map[index], 1 << offset);
+ rtems_rfs_buffer_mark_dirty (control->buffer);
+ control->free++;
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_map_test (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit bit,
+ bool* state)
+{
+ rtems_rfs_bitmap_map map;
+ int index;
+ int rc;
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+ if (bit >= control->size)
+ return EINVAL;
+ index = rtems_rfs_bitmap_map_index (bit);
+ *state = rtems_rfs_bitmap_test (map[index], bit);
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_map_set_all (rtems_rfs_bitmap_control* control)
+{
+ rtems_rfs_bitmap_map map;
+ size_t elements;
+ int e;
+ int rc;
+
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+
+ elements = rtems_rfs_bitmap_elements (control->size);
+
+ control->free = 0;
+
+ for (e = 0; e < elements; e++)
+ map[e] = RTEMS_RFS_BITMAP_ELEMENT_SET;
+
+ elements = rtems_rfs_bitmap_elements (elements);
+
+ for (e = 0; e < elements; e++)
+ control->search_bits[e] = RTEMS_RFS_BITMAP_ELEMENT_SET;
+
+ rtems_rfs_buffer_mark_dirty (control->buffer);
+
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_map_clear_all (rtems_rfs_bitmap_control* control)
+{
+ rtems_rfs_bitmap_map map;
+ rtems_rfs_bitmap_bit last_search_bit;
+ size_t elements;
+ int e;
+ int rc;
+
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+
+ elements = rtems_rfs_bitmap_elements (control->size);
+
+ control->free = elements;
+
+ for (e = 0; e < elements; e++)
+ map[e] = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
+
+ /*
+ * Set the un-mapped bits in the last search element so the available logic
+ * works.
+ */
+ last_search_bit = rtems_rfs_bitmap_map_offset (elements);
+
+ if (last_search_bit == 0)
+ last_search_bit = rtems_rfs_bitmap_element_bits ();
+
+ elements = rtems_rfs_bitmap_elements (elements);
+
+ for (e = 0; e < (elements - 1); e++)
+ control->search_bits[e] = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
+
+ control->search_bits[elements - 1] =
+ rtems_rfs_bitmap_merge (RTEMS_RFS_BITMAP_ELEMENT_CLEAR,
+ RTEMS_RFS_BITMAP_ELEMENT_SET,
+ rtems_rfs_bitmap_mask (last_search_bit));
+
+ rtems_rfs_buffer_mark_dirty (control->buffer);
+
+ return 0;
+}
+
+static int
+rtems_rfs_search_map_for_clear_bit (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit* bit,
+ bool* found,
+ size_t window,
+ int direction)
+{
+ rtems_rfs_bitmap_map map;
+ rtems_rfs_bitmap_bit test_bit;
+ rtems_rfs_bitmap_bit end_bit;
+ rtems_rfs_bitmap_element* search_bits;
+ int search_index;
+ int search_offset;
+ rtems_rfs_bitmap_element* map_bits;
+ int map_index;
+ int map_offset;
+ int rc;
+
+ *found = false;
+
+ /*
+ * Load the bitmap.
+ */
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+
+ /*
+ * Calculate the bit we are testing plus the end point we search over.
+ */
+ test_bit = *bit;
+ end_bit = test_bit + (window * direction);
+
+ if (end_bit < 0)
+ end_bit = 0;
+ else if (end_bit >= control->size)
+ end_bit = control->size - 1;
+
+ map_index = rtems_rfs_bitmap_map_index (test_bit);
+ map_offset = rtems_rfs_bitmap_map_offset (test_bit);
+ search_index = rtems_rfs_bitmap_map_index (map_index);
+ search_offset = rtems_rfs_bitmap_map_offset (map_index);
+
+ search_bits = &control->search_bits[search_index];
+ map_bits = &map[map_index];
+
+ /*
+ * Check each bit from the search map offset for a clear bit.
+ */
+ do
+ {
+ /*
+ * If any bit is clear find that bit and then search the map element. If
+ * all bits are set there are no map bits so move to the next search
+ * element.
+ */
+ if (!rtems_rfs_bitmap_match (*search_bits, RTEMS_RFS_BITMAP_ELEMENT_SET))
+ {
+ while ((search_offset >= 0)
+ && (search_offset < rtems_rfs_bitmap_element_bits ()))
+ {
+ if (!rtems_rfs_bitmap_test (*search_bits, search_offset))
+ {
+ /*
+ * Find the clear bit in the map. Update the search map and map if
+ * found. We may find none are spare if searching up from the seed.
+ */
+ while ((map_offset >= 0)
+ && (map_offset < rtems_rfs_bitmap_element_bits ()))
+ {
+ if (!rtems_rfs_bitmap_test (*map_bits, map_offset))
+ {
+ *map_bits = rtems_rfs_bitmap_set (*map_bits, 1 << map_offset);
+ if (rtems_rfs_bitmap_match(*map_bits,
+ RTEMS_RFS_BITMAP_ELEMENT_SET))
+ *search_bits = rtems_rfs_bitmap_set (*search_bits,
+ 1 << search_offset);
+ control->free--;
+ *bit = test_bit;
+ *found = true;
+ rtems_rfs_buffer_mark_dirty (control->buffer);
+ return 0;
+ }
+
+ if (test_bit == end_bit)
+ break;
+
+ map_offset += direction;
+ test_bit += direction;
+ }
+ }
+
+ map_bits += direction;
+ map_index += direction;
+ map_offset = direction > 0 ? 0 : rtems_rfs_bitmap_element_bits () - 1;
+
+ test_bit = (map_index * rtems_rfs_bitmap_element_bits ()) + map_offset;
+
+ search_offset += direction;
+
+ if (((direction < 0) && (test_bit <= end_bit))
+ || ((direction > 0) && (test_bit >= end_bit)))
+ break;
+ }
+ }
+ else
+ {
+ /*
+ * Move to the next search element. We need to determine the number of
+ * bits in the search offset that are being skipped so the map bits
+ * pointer can be updated. If we are moving down and we have a search
+ * offset of 0 then the search map adjustment is to the top bit of the
+ * pervious search bit's value.
+ *
+ * Align test_bit either up or down depending on the direction to next 32
+ * bit boundary.
+ */
+ rtems_rfs_bitmap_bit bits_skipped;
+ test_bit &= ~((1 << RTEMS_RFS_ELEMENT_BITS_POWER_2) - 1);
+ if (direction > 0)
+ {
+ bits_skipped = rtems_rfs_bitmap_element_bits () - search_offset;
+ test_bit += bits_skipped * rtems_rfs_bitmap_element_bits ();
+ map_offset = 0;
+ }
+ else
+ {
+ bits_skipped = search_offset + 1;
+ /*
+ * Need to remove 1 for the rounding up. The above rounds down and
+ * adds 1. Remember the logic is for subtraction.
+ */
+ test_bit -= ((bits_skipped - 1) * rtems_rfs_bitmap_element_bits ()) + 1;
+ map_offset = rtems_rfs_bitmap_element_bits () - 1;
+ }
+ map_bits += direction * bits_skipped;
+ map_index += direction * bits_skipped;
+ }
+
+ search_bits += direction;
+ search_offset = direction > 0 ? 0 : rtems_rfs_bitmap_element_bits () - 1;
+ }
+ while (((direction < 0) && (test_bit >= end_bit))
+ || ((direction > 0) && (test_bit <= end_bit)));
+
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_map_alloc (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit seed,
+ bool* allocated,
+ rtems_rfs_bitmap_bit* bit)
+{
+ rtems_rfs_bitmap_bit upper_seed;
+ rtems_rfs_bitmap_bit lower_seed;
+ rtems_rfs_bitmap_bit window; /* may become a parameter */
+ int rc = 0;
+
+ /*
+ * By default we assume the allocation failed.
+ */
+ *allocated = false;
+
+ /*
+ * The window is the number of bits we search over in either direction each
+ * time.
+ */
+ window = RTEMS_RFS_BITMAP_SEARCH_WINDOW;
+
+ /*
+ * Start from the seed and move in either direction. Search in window amounts
+ * of bits from the original seed above then below. That is search from the
+ * seed up then from the seed down a window number of bits, then repeat the
+ * process from the window distance from the seed, again above then
+ * below. Keep moving out until all bits have been searched.
+ */
+ upper_seed = seed;
+ lower_seed = seed;
+
+ /*
+ * If the upper and lower seed values have reached the limits of the bitmap
+ * we have searched all of the map. The seed may not be aligned to a window
+ * boundary so we may need to search a partial window and this may also not
+ * be balanced for the upper or lower seeds. We move to the limits, search
+ * then return false if no clear bits are found.
+ */
+ while (((upper_seed >= 0) && (upper_seed < control->size))
+ || ((lower_seed >= 0) && (lower_seed < control->size)))
+ {
+ /*
+ * Search up first so bits allocated in succession are grouped together.
+ */
+ if (upper_seed < control->size)
+ {
+ *bit = upper_seed;
+ rc = rtems_rfs_search_map_for_clear_bit (control, bit, allocated,
+ window, 1);
+ if ((rc > 0) || *allocated)
+ break;
+ }
+
+ if (lower_seed >= 0)
+ {
+ *bit = lower_seed;
+ rc = rtems_rfs_search_map_for_clear_bit (control, bit, allocated,
+ window, -1);
+ if ((rc > 0) || *allocated)
+ break;
+ }
+
+ /*
+ * Do not bound the limits at the edges of the map. Do not update if an
+ * edge has been passed.
+ */
+ if (upper_seed < control->size)
+ upper_seed += window;
+ if (lower_seed >= 0)
+ lower_seed -= window;
+ }
+
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_create_search (rtems_rfs_bitmap_control* control)
+{
+ rtems_rfs_bitmap_map search_map;
+ rtems_rfs_bitmap_map map;
+ size_t size;
+ rtems_rfs_bitmap_bit bit;
+ int rc;
+
+ rc = rtems_rfs_bitmap_load_map (control, &map);
+ if (rc > 0)
+ return rc;
+
+ control->free = 0;
+ search_map = control->search_bits;
+ size = control->size;
+ bit = 0;
+
+ *search_map = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
+ while (size)
+ {
+ rtems_rfs_bitmap_element bits;
+ int available;
+ if (size < rtems_rfs_bitmap_element_bits ())
+ {
+ bits = rtems_rfs_bitmap_merge (*map,
+ RTEMS_RFS_BITMAP_ELEMENT_SET,
+ rtems_rfs_bitmap_mask_section (0, size));
+ available = size;
+ }
+ else
+ {
+ bits = *map;
+ available = rtems_rfs_bitmap_element_bits ();
+ }
+
+ if (rtems_rfs_bitmap_match (bits, RTEMS_RFS_BITMAP_ELEMENT_SET))
+ rtems_rfs_bitmap_set (*search_map, bit);
+ else
+ {
+ int b;
+ for (b = 0; b < available; b++)
+ if (!rtems_rfs_bitmap_test (bits, b))
+ control->free++;
+ }
+
+ size -= available;
+
+ if (bit == rtems_rfs_bitmap_element_bits ())
+ {
+ bit = 0;
+ search_map++;
+ *search_map = RTEMS_RFS_BITMAP_ELEMENT_CLEAR;
+ }
+ else
+ bit++;
+ map++;
+ }
+
+ return 0;
+}
+
+int
+rtems_rfs_bitmap_open (rtems_rfs_bitmap_control* control,
+ rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* buffer,
+ size_t size,
+ rtems_rfs_buffer_block block)
+{
+ size_t elements = rtems_rfs_bitmap_elements (size);
+
+ control->buffer = buffer;
+ control->fs = fs;
+ control->block = block;
+ control->size = size;
+
+ elements = rtems_rfs_bitmap_elements (elements);
+ control->search_bits = malloc (elements * sizeof (rtems_rfs_bitmap_element));
+
+ if (!control->search_bits)
+ return ENOMEM;
+
+ return rtems_rfs_bitmap_create_search (control);
+}
+
+int
+rtems_rfs_bitmap_close (rtems_rfs_bitmap_control* control)
+{
+ free (control->search_bits);
+ return 0;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.h b/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.h
new file mode 100644
index 0000000000..8fe9ab7c9b
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-bitmaps.h
@@ -0,0 +1,305 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Bitmap Routines.
+ *
+ * These functions manage bit maps. A bit map consists of the map of bit
+ * allocated in a block and a search map where a bit represents 32 actual
+ * bits. The search map allows for a faster search for an available bit as 32
+ * search bits can checked in a test.
+ */
+
+#if !defined (_RTEMS_RFS_BITMAPS_H_)
+#define _RTEMS_RFS_BITMAPS_H_
+
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-file-system-fwd.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+/**
+ * Define the way the bits are configured. We can have them configured as clear
+ * being 0 or clear being 1. This does not effect how masks are defined. A mask
+ * always has a 1 for set and 0 for clear.
+ */
+#define RTEMS_RFS_BITMAP_CLEAR_ZERO 0
+
+#if RTEMS_RFS_BITMAP_CLEAR_ZERO
+/*
+ * Bit set is a 1 and clear is 0.
+ */
+#define RTEMS_RFS_BITMAP_BIT_CLEAR 0
+#define RTEMS_RFS_BITMAP_BIT_SET 1
+#define RTEMS_RFS_BITMAP_ELEMENT_SET (RTEMS_RFS_BITMAP_ELEMENT_FULL_MASK)
+#define RTEMS_RFS_BITMAP_ELEMENT_CLEAR (0)
+#define RTEMS_RFS_BITMAP_SET_BITS(_t, _b) ((_t) | (_b))
+#define RTEMS_RFS_BITMAP_CLEAR_BITS(_t, _b) ((_t) & ~(_b))
+#define RTEMS_RFS_BITMAP_TEST_BIT(_t, _b) (((_t) & (1 << (_b))) != 0 ? true : false)
+#else
+/*
+ * Bit set is a 0 and clear is 1.
+ */
+#define RTEMS_RFS_BITMAP_BIT_CLEAR 1
+#define RTEMS_RFS_BITMAP_BIT_SET 0
+#define RTEMS_RFS_BITMAP_ELEMENT_SET (0)
+#define RTEMS_RFS_BITMAP_ELEMENT_CLEAR (RTEMS_RFS_BITMAP_ELEMENT_FULL_MASK)
+#define RTEMS_RFS_BITMAP_SET_BITS(_t, _b) ((_t) & ~(_b))
+#define RTEMS_RFS_BITMAP_CLEAR_BITS(_t, _b) ((_t) | (_b))
+#define RTEMS_RFS_BITMAP_TEST_BIT(_t, _b) (((_t) & (1 << (_b))) == 0 ? true : false)
+#endif
+
+/**
+ * Invert a mask. Masks are always 1 for set and 0 for clear.
+ */
+#define RTEMS_RFS_BITMAP_INVERT_MASK(_mask) (~(_mask))
+
+/**
+ * This is the full mask of the length of the element. A mask is always a 1 for
+ * set and 0 for clear. It is not effected by the state of
+ * RTEMS_RFS_BITMAP_CLEAR_ZERO.
+ */
+#define RTEMS_RFS_BITMAP_ELEMENT_FULL_MASK (0xffffffffUL)
+
+/**
+ * The bitmap search window. Searches occur around a seed in either direction
+ * for half the window.
+ */
+#define RTEMS_RFS_BITMAP_SEARCH_WINDOW (rtems_rfs_bitmap_element_bits () * 64)
+
+/**
+ * A bit in a map.
+ */
+typedef int32_t rtems_rfs_bitmap_bit;
+
+/**
+ * The basic element of a bitmap. A bitmap is manipulated by elements.
+ */
+typedef uint32_t rtems_rfs_bitmap_element;
+
+/**
+ * The power of 2 number of bits in the element.
+ */
+#define RTEMS_RFS_ELEMENT_BITS_POWER_2 (5)
+
+/**
+ * A bitmap or map is an array of bitmap elements.
+ */
+typedef rtems_rfs_bitmap_element* rtems_rfs_bitmap_map;
+
+/**
+ * The bitmap control is a simple way to manage the various parts of a bitmap.
+ */
+struct rtems_rfs_bitmap_control_t
+{
+ rtems_rfs_buffer_handle* buffer; //< Handle the to buffer with the bit
+ //map.
+ rtems_rfs_file_system* fs; //< The map's file system.
+ rtems_rfs_buffer_block block; //< The map's block number on disk.
+ size_t size; //< Number of bits in the map. Passed
+ //to create.
+ size_t free; //< Number of bits in the map that are
+ //free (clear).
+ rtems_rfs_bitmap_map search_bits; //< The search bit map memory.
+};
+
+typedef struct rtems_rfs_bitmap_control_t rtems_rfs_bitmap_control;
+
+/**
+ * Return the number of bits for the number of bytes provided.
+ */
+#define rtems_rfs_bitmap_numof_bits(_bytes) (8 * (_bytes))
+
+/**
+ * Return the number of bits for the number of bytes provided. The search
+ * element and the element must have the same number of bits.
+ */
+#define rtems_rfs_bitmap_element_bits() \
+ rtems_rfs_bitmap_numof_bits (sizeof (rtems_rfs_bitmap_element))
+
+/**
+ * Return the number of bits a search element covers.
+ */
+#define rtems_rfs_bitmap_search_element_bits() \
+ (rtems_rfs_bitmap_element_bits() * rtems_rfs_bitmap_element_bits())
+
+/**
+ * Return the number of elements for a given number of bits.
+ */
+#define rtems_rfs_bitmap_elements(_bits) \
+ ((((_bits) - 1) / rtems_rfs_bitmap_element_bits()) + 1)
+
+/**
+ * Release the bitmap buffer back to the buffer pool or cache.
+ */
+#define rtems_rfs_bitmap_release_buffer(_fs, _bm) \
+ rtems_rfs_buffer_handle_release (_fs, (_bm)->buffer)
+
+/**
+ * Return the element index for a given bit. We use a macro to hide any
+ * implementation assuptions. Typically this would be calculated by dividing
+ * the bit index by the number of bits in an element. Given we have a power of
+ * 2 as the number of bits we can avoid the division by using a shift. A good
+ * compiler should figure this out but I would rather enforce this than rely on
+ * the specific backend of a compiler to do the right thing.
+ */
+#define rtems_rfs_bitmap_map_index(_b) \
+ ((_b) >> RTEMS_RFS_ELEMENT_BITS_POWER_2)
+
+/**
+ * Return the bit offset for a given bit in an element in a map. See @ref
+ * rtems_rfs_bitmap_map_index for a detailed reason why.
+ */
+#define rtems_rfs_bitmap_map_offset(_b) \
+ ((_b) & ((1 << RTEMS_RFS_ELEMENT_BITS_POWER_2) - 1))
+
+/**
+ * Return the size of the bitmap.
+ */
+#define rtems_rfs_bitmap_map_size(_c) ((_c)->size)
+
+/**
+ * Return the number of free bits in the bitmap.
+ */
+#define rtems_rfs_bitmap_map_free(_c) ((_c)->free)
+
+/**
+ * Return the buffer handle.
+ */
+#define rtems_rfs_bitmap_map_handle(_c) ((_c)->buffer)
+
+/**
+ * Return the bitmap map block.
+ */
+#define rtems_rfs_bitmap_map_block(_c) ((_c)->block)
+
+/**
+ * Create a bit mask with the specified number of bits up to an element's
+ * size. The mask is aligned to bit 0 of the element.
+ *
+ * @param size The number of bits in the mask.
+ * @return The mask of the argument size number of bits.
+ */
+rtems_rfs_bitmap_element rtems_rfs_bitmap_mask (unsigned int size);
+
+/**
+ * Create a bit mask section. A mask section is a mask that is not aligned to
+ * an end of the element.
+ *
+ * @param start The first bit of the mask numbered from 0.
+ * @param end The end bit of the mask numbered from 0.
+ * @return Mask section as defined by the start and end arguments.
+ */
+rtems_rfs_bitmap_element rtems_rfs_bitmap_mask_section (unsigned int start,
+ unsigned int end);
+
+/**
+ * Set a bit in a map and if all the bits are set, set the search map bit as
+ * well.
+ *
+ * @param control The control for the map.
+ * @param bit The bit in the map to set.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_map_set (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit bit);
+
+/**
+ * Clear a bit in a map and make sure the search map bit is clear so a search
+ * will find this bit available.
+ *
+ * @param control The control for the map.
+ * @param bit The bit in the map to clear.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_map_clear (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit bit);
+
+/**
+ * Test a bit in the map.
+ *
+ * @param control The bitmap control.
+ * @param bit The bit to test.
+ * @param state The state of the bit if no error is returned.
+ * @return int The error number (errno). No error if 0.
+ */
+int
+rtems_rfs_bitmap_map_test (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit bit,
+ bool* state);
+
+/**
+ * Set all bits in the bitmap and set the dirty bit.
+ *
+ * @param control The bitmap control.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_map_set_all (rtems_rfs_bitmap_control* control);
+
+/**
+ * Clear all bits in the bitmap and set the dirty bit.
+ *
+ * @param control The bitmap control.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_map_clear_all (rtems_rfs_bitmap_control* control);
+
+/**
+ * Find a free bit searching from the seed up and down until found. The search
+ * is performing by moving up from the seed for the window distance then to
+ * search down from the seed for the window distance. This is repeated out from
+ * the seed for each window until a free bit is found. The search is performed
+ * by checking the search map to see if the map has a free bit.
+ *
+ * @param control The map control.
+ * @param seed The bit to search out from.
+ * @param allocate A bit was allocated.
+ * @param bit Returns the bit found free if true is returned.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_map_alloc (rtems_rfs_bitmap_control* control,
+ rtems_rfs_bitmap_bit seed,
+ bool* allocate,
+ rtems_rfs_bitmap_bit* bit);
+
+/**
+ * Create a search bit map from the actual bit map.
+ *
+ * @param control The map control.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_create_search (rtems_rfs_bitmap_control* control);
+
+/**
+ * Open a bitmap control with a map and search map.
+ *
+ * @param control The map control.
+ * @param fs The file system data.
+ * @param buffer The buffer handle the map is stored in.
+ * @param size The number of bits in the map.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_open (rtems_rfs_bitmap_control* control,
+ rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* buffer,
+ size_t size,
+ rtems_rfs_buffer_block block);
+
+/**
+ * Close a bitmap.
+ *
+ * @param control The bit map control.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_bitmap_close (rtems_rfs_bitmap_control* control);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-block-pos.h b/cpukit/libfs/src/rfs/rtems-rfs-block-pos.h
new file mode 100644
index 0000000000..899e915695
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-block-pos.h
@@ -0,0 +1,233 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Block Position and Size Management.
+ *
+ * These functions manage the position in a block map as well as a size of data
+ * held in a block map. The position is the block count plus the offset into
+ * the last block where a block position of 0 and an offset of 0 is the start
+ * of a map. The size has a block count plus an offset, but the offset into the
+ * last block gives the actual size of the data in the map. This means a size
+ * will always have a block count greater than 0 when the file is not empty. A
+ * size offset of 0 and a non-zero block count means the length if aligned to
+ * the end of the block. For this reason there are 2 similar types so we know
+ * which set of rules are in use and the reason for this file.
+ */
+
+#if !defined (_RTEMS_RFS_BLOCK_POS_H_)
+#define _RTEMS_RFS_BLOCK_POS_H_
+
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+
+/**
+ * The block number is the same type as the inode block number. This makes sure
+ * the sizes of the types match.
+ */
+typedef rtems_rfs_inode_block rtems_rfs_block_no;
+
+/**
+ * The offset into a block.
+ */
+typedef uint32_t rtems_rfs_block_off;
+
+/**
+ * A block position is a block number times the block size plus the offset. The
+ * block field can be used hold a block number for the position as a look up
+ * cache.
+ */
+typedef struct rtems_rfs_block_pos_t
+{
+ /**
+ * The block index in the map. Range is from 0 to the maps block count minus
+ * 1.
+ */
+ rtems_rfs_block_no bno;
+
+ /**
+ * The offset into the block. Must be less than the block size.
+ */
+ rtems_rfs_block_off boff;
+
+ /**
+ * The block number that the bpos + boff map to. The 0 value is invalid and
+ * means no block number has been set.
+ */
+ rtems_rfs_block_no block;
+
+} rtems_rfs_block_pos;
+
+/**
+ * Copy a block position.
+ *
+ * @param _lhs The left hand side.
+ * @parma _rhs The right handl side.
+ */
+#define rtems_rfs_block_copy_bpos(_lhs, _rhs) \
+ do { (_lhs)->bno = (_rhs)->bno; \
+ (_lhs)->boff = (_rhs)->boff; \
+ (_lhs)->block = (_rhs)->block; } while (0)
+
+/**
+ * Zero a block position.
+ *
+ * @param bpos A pointer to the block position.
+ */
+static inline void
+rtems_rfs_block_set_bpos_zero (rtems_rfs_block_pos* bpos)
+{
+ bpos->bno = 0;
+ bpos->boff = 0;
+ bpos->block = 0;
+}
+
+/**
+ * Given a position compute the block number and block offset.
+ *
+ * @param fs The file system data.
+ * @param pos The position as an absolute offset from the start.
+ * @param bpos Pointer to the block position to fill in.
+ */
+void rtems_rfs_block_get_bpos (rtems_rfs_file_system* fs,
+ rtems_rfs_pos pos,
+ rtems_rfs_block_pos* bpos);
+
+/**
+ * Given a block position compute the absolute offset.
+ *
+ * @param fs The file system data.
+ * @param bpos Pointer to the block position to fill in.
+ * @return rtems_rfs_pos The absolute offset.
+ */
+rtems_rfs_pos rtems_rfs_block_get_pos (rtems_rfs_file_system* fs,
+ rtems_rfs_block_pos* bpos);
+
+/**
+ * Add the relative position to the block position. The relative position is
+ * signed.
+ *
+ * @param fs The file system data.
+ * @param offset The relative offset add to the block position.
+ * @param bpos Pointer to the block position to fill in.
+ */
+static inline void
+rtems_rfs_block_add_pos (rtems_rfs_file_system* fs,
+ rtems_rfs_pos_rel offset,
+ rtems_rfs_block_pos* bpos)
+{
+ rtems_rfs_block_get_bpos (fs,
+ rtems_rfs_block_get_pos (fs, bpos) + offset,
+ bpos);
+ bpos->block = 0;
+}
+
+/**
+ * A block size is the number of blocks less one plus the offset where the
+ * offset must be less than the block size.
+ */
+typedef struct rtems_rfs_block_size_t
+{
+ /**
+ * The count of blocks in a map. A 0 means no blocks and a zero length and
+ * the offset should also be 0.
+ */
+ rtems_rfs_block_no count;
+
+ /**
+ * The offset into the block. An offset of 0 means block size, ie the first
+ * byte of the next block which is not allocated.
+ */
+ rtems_rfs_block_off offset;
+
+} rtems_rfs_block_size;
+
+/**
+ * Copy a block size.
+ *
+ * @param _lhs The left hand side.
+ * @parma _rhs The right handl side.
+ */
+#define rtems_rfs_block_copy_size(_lhs, _rhs) \
+ do { (_lhs)->count = (_rhs)->count; \
+ (_lhs)->offset = (_rhs)->offset; } while (0)
+
+/**
+ * Last block ?
+ */
+#define rtems_rfs_block_pos_last_block(_p, _s) \
+ ((((_p)->bno == 0) && ((_s)->count == 0)) || ((_p)->bno == ((_s)->count - 1)))
+
+/**
+ * Last block ?
+ */
+#define rtems_rfs_block_pos_past_end(_p, _s) \
+ (((_p)->bno && ((_s)->count == 0)) || \
+ ((_p)->bno >= (_s)->count) || \
+ (((_p)->bno == ((_s)->count - 1)) && ((_p)->boff > (_s)->offset)))
+
+/**
+ * Is the block position past the end.
+ */
+#define rtems_rfs_block_pos_block_past_end(_p, _s) \
+ (((_p)->bno && ((_s)->count == 0)) || ((_p)->bno >= (_s)->count))
+
+/**
+ * Copy the size to the block position. Note the block position and the size
+ * have different block counts.
+ */
+#define rtems_rfs_block_size_get_bpos(_s, _b) \
+ do { (_b)->bno = (_s)->count; \
+ (_b)->boff = (_s)->offset; \
+ (_b)->block = 0; \
+ if ((_b)->boff) --(_b)->bno; } while (0)
+
+/**
+ * Zero a block size.
+ *
+ * @param size A pointer to the block size.
+ */
+static inline void
+rtems_rfs_block_set_size_zero (rtems_rfs_block_size* size)
+{
+ size->count = 0;
+ size->offset = 0;
+}
+
+/**
+ * Set the size given a position.
+ *
+ * @param fs The file system data.
+ * @param pos The position as an absolute offset from the start.
+ * @param size Pointer to the block size to fill in.
+ */
+void rtems_rfs_block_get_block_size (rtems_rfs_file_system* fs,
+ rtems_rfs_pos pos,
+ rtems_rfs_block_size* size);
+
+/**
+ * Calculate the position given the number of blocks and the offset. If the
+ * block count is 0 the size is 0. If the block is greater than 0 and the
+ * offset is 0 the size is number of blocks multipled by the block size and if
+ * the offset is not 0 it is the offset into the last block. For example if
+ * blocks is 1 and offset is 0 the size is the block size. If the block count
+ * is 1 and size is 100 the size is 100.
+ *
+ * @param fs The file system data.
+ * @param size The size in blocks and offset.
+ * @return rtems_rfs_pos The size in bytes.
+ */
+rtems_rfs_pos rtems_rfs_block_get_size (rtems_rfs_file_system* fs,
+ rtems_rfs_block_size* size);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-block.c b/cpukit/libfs/src/rfs/rtems-rfs-block.c
new file mode 100644
index 0000000000..e8542d6685
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-block.c
@@ -0,0 +1,800 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Block Routines.
+ *
+ * These functions manage blocks in the RFS file system. A block is an area of
+ * the media and its size is set for a each specific media. The block size is
+ * set when the file system is set up and needs to be matched for it to be read
+ * correctly.
+ *
+ * Blocks are managed as groups. A block group or "group" is part of the total
+ * number of blocks being managed by the file system and exist to allow
+ * resources to localised. A file in a directory will be allocated blocks in
+ * the same group as the directory, and the blocks for the file will also be
+ * allocated in the same group.
+ *
+ * A group consist of a block bitmap, inodes and data blocks. The first block
+ * of the file system will hold the superblock. The block bitmap is a
+ * collection of blocks that hold a map of bits, one bit per block for each
+ * block in the group. When a file system is mounted the block bitmaps are read
+ * and a summary bit map is made. The summary bitmap has a single bit for 32
+ * bits in the bitmap and is set when all 32 bits it maps to are set. This
+ * speeds up the search for a free block by a factor of 32.
+ */
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-group.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+
+void
+rtems_rfs_block_get_bpos (rtems_rfs_file_system* fs,
+ rtems_rfs_pos pos,
+ rtems_rfs_block_pos* bpos)
+{
+ bpos->bno = pos / rtems_rfs_fs_block_size (fs);
+ bpos->boff = pos % rtems_rfs_fs_block_size (fs);
+}
+
+rtems_rfs_pos
+rtems_rfs_block_get_pos (rtems_rfs_file_system* fs,
+ rtems_rfs_block_pos* bpos)
+{
+ rtems_rfs_pos pos = 0;
+ if (bpos->bno)
+ {
+ pos = bpos->boff;
+ if (pos == 0)
+ pos = rtems_rfs_fs_block_size (fs);
+ pos += (bpos->bno - 1) * rtems_rfs_fs_block_size (fs);
+ }
+ return pos;
+}
+
+void
+rtems_rfs_block_get_block_size (rtems_rfs_file_system* fs,
+ rtems_rfs_pos pos,
+ rtems_rfs_block_size* size)
+{
+ if (pos == 0)
+ rtems_rfs_block_set_size_zero (size);
+ else
+ {
+ size->count = pos / rtems_rfs_fs_block_size (fs) + 1;
+ size->offset = pos % rtems_rfs_fs_block_size (fs);
+ }
+}
+
+rtems_rfs_pos
+rtems_rfs_block_get_size (rtems_rfs_file_system* fs,
+ rtems_rfs_block_size* size)
+{
+ uint32_t offset;
+ if (size->count == 0)
+ return 0;
+ if (size->offset == 0)
+ offset = rtems_rfs_fs_block_size (fs);
+ else
+ offset = size->offset;
+ return (((uint64_t) (size->count - 1)) * rtems_rfs_fs_block_size (fs)) + offset;
+}
+
+int
+rtems_rfs_block_map_open (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* inode,
+ rtems_rfs_block_map* map)
+{
+ int b;
+ int rc;
+
+ /*
+ * Set the count to 0 so at least find fails, then open the handle and make
+ * sure the inode has been loaded into memory. If we did not load the inode
+ * do not unload it. The caller may assume it is still loaded when we return.
+ */
+
+ map->dirty = false;
+ map->inode = NULL;
+ rtems_rfs_block_set_size_zero (&map->size);
+ rtems_rfs_block_set_bpos_zero (&map->bpos);
+
+ rc = rtems_rfs_buffer_handle_open (fs, &map->singly_buffer);
+ if (rc > 0)
+ return rc;
+ rc = rtems_rfs_buffer_handle_open (fs, &map->doubly_buffer);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_inode_load (fs, inode);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &map->singly_buffer);
+ rtems_rfs_buffer_handle_close (fs, &map->doubly_buffer);
+ return rc;
+ }
+
+ /*
+ * Extract the block and block count data from the inode into the targets
+ * byte order.
+ */
+ map->inode = inode;
+ for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
+ map->blocks[b] = rtems_rfs_inode_get_block (inode, b);
+ map->size.count = rtems_rfs_inode_get_block_count (inode);
+ map->size.offset = rtems_rfs_inode_get_block_offset (inode);
+ map->last_map_block = rtems_rfs_inode_get_last_map_block (inode);
+ map->last_data_block = rtems_rfs_inode_get_last_data_block (inode);
+
+ rc = rtems_rfs_inode_unload (fs, inode, false);
+
+ return rc;
+}
+
+int
+rtems_rfs_block_map_close (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map)
+{
+ int rc = 0;
+ int brc;
+
+ if (map->dirty && map->inode)
+ {
+ brc = rtems_rfs_inode_load (fs, map->inode);
+ if (brc > 0)
+ rc = brc;
+
+ if (rc == 0)
+ {
+ int b;
+
+ for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
+ rtems_rfs_inode_set_block (map->inode, b, map->blocks[b]);
+ rtems_rfs_inode_set_block_count (map->inode, map->size.count);
+ rtems_rfs_inode_set_block_offset (map->inode, map->size.offset);
+ rtems_rfs_inode_set_last_map_block (map->inode, map->last_map_block);
+ rtems_rfs_inode_set_last_data_block (map->inode, map->last_data_block);
+
+ brc = rtems_rfs_inode_unload (fs, map->inode, true);
+ if (brc > 0)
+ rc = brc;
+
+ map->dirty = false;
+ }
+ }
+
+ map->inode = NULL;
+
+ brc = rtems_rfs_buffer_handle_close (fs, &map->singly_buffer);
+ if ((brc > 0) && (rc == 0))
+ rc = brc;
+ brc = rtems_rfs_buffer_handle_close (fs, &map->doubly_buffer);
+ if ((brc > 0) && (rc == 0))
+ rc = brc;
+ return rc;
+}
+
+/**
+ * Find a block indirectly held in a table of block numbers.
+ *
+ * @param fs The file system.
+ * @param buffer The handle to access the block data by.
+ * @param block The block number of the table of block numbers.
+ * @param offset The offset in the table of the block number to return. This is
+ * a block number offset not a byte offset into the table.
+ * @param result Pointer to the result of the search.
+ * @return int The error number (errno). No error if 0.
+ */
+static int
+rtems_rfs_block_find_indirect (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* buffer,
+ rtems_rfs_block_no block,
+ int offset,
+ rtems_rfs_block_no* result)
+{
+ int rc;
+
+ /*
+ * If the handle has a buffer and this request is a different block the current
+ * buffer is released.
+ */
+ rc = rtems_rfs_buffer_handle_request (fs, buffer, block, true);
+ if (rc > 0)
+ return rc;
+
+ *result = rtems_rfs_block_get_number (buffer, offset);
+ if ((*result + 1) == 0)
+ *result = 0;
+
+ if (*result >= rtems_rfs_fs_blocks (fs))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_FIND))
+ printf ("rtems-rfs: block-find: invalid block in table:" \
+ " block=%ld, indirect=%ld/%d\n", *result, block, offset);
+ *result = 0;
+ rc = EIO;
+ }
+
+ return 0;
+}
+
+int
+rtems_rfs_block_map_find (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_block_pos* bpos,
+ rtems_rfs_block_no* block)
+{
+ int rc = 0;
+
+ *block = 0;
+
+ /*
+ * Range checking here makes the remaining logic simpler.
+ */
+ if (rtems_rfs_block_pos_block_past_end (bpos, &map->size))
+ return ENXIO;
+
+ /*
+ * If the block position is the same and we have found the block just return it.
+ */
+ if ((bpos->bno == map->bpos.bno) && (map->bpos.block != 0))
+ {
+ *block = map->bpos.block;
+ }
+ else
+ {
+ /*
+ * Determine the type of access we need to perform. If the number of blocks
+ * is less than or equal to the number of slots in the inode the blocks are
+ * directly accessed.
+ */
+ if (map->size.count <= RTEMS_RFS_INODE_BLOCKS)
+ {
+ *block = map->blocks[bpos->bno];
+ }
+ else
+ {
+ /*
+ * The map is either singly or doubly indirect.
+ */
+ rtems_rfs_block_no direct;
+ rtems_rfs_block_no singly;
+
+ direct = bpos->bno % fs->blocks_per_block;
+ singly = bpos->bno / fs->blocks_per_block;
+
+ if (map->size.count <= fs->block_map_singly_blocks)
+ {
+ /*
+ * This is a single indirect table of blocks anchored off a slot in the
+ * inode.
+ */
+ rc = rtems_rfs_block_find_indirect (fs,
+ &map->singly_buffer,
+ map->blocks[singly],
+ direct, block);
+ }
+ else
+ {
+ /*
+ * The map is doubly indirect.
+ */
+ rtems_rfs_block_no doubly;
+
+ doubly = singly / fs->blocks_per_block;
+ singly %= fs->blocks_per_block;
+
+ if (map->size.count < fs->block_map_doubly_blocks)
+ {
+ rc = rtems_rfs_block_find_indirect (fs,
+ &map->doubly_buffer,
+ map->blocks[doubly],
+ singly, &singly);
+ if (rc == 0)
+ {
+ rc = rtems_rfs_block_find_indirect (fs,
+ &map->singly_buffer,
+ singly, direct, block);
+ }
+ }
+ else
+ {
+ /*
+ * This should never happen. Here so Joel can remove once his coverage
+ * testing gets to the file systems.
+ */
+ rc = ENXIO;
+ }
+ }
+ }
+ }
+
+ if (rc == 0)
+ {
+ rtems_rfs_block_copy_bpos (&map->bpos, bpos);
+ map->bpos.block = *block;
+ }
+
+ return rc;
+}
+
+int
+rtems_rfs_block_map_seek (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_pos_rel offset,
+ rtems_rfs_block_no* block)
+{
+ rtems_rfs_block_pos bpos;
+ rtems_rfs_block_copy_bpos (&bpos, &map->bpos);
+ rtems_rfs_block_add_pos (fs, offset, &bpos);
+ return rtems_rfs_block_map_find (fs, map, &bpos, block);
+}
+
+int
+rtems_rfs_block_map_next_block (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_block_no* block)
+{
+ rtems_rfs_block_pos bpos;
+ bpos.bno = map->bpos.bno + 1;
+ bpos.boff = 0;
+ bpos.block = 0;
+ return rtems_rfs_block_map_find (fs, map, &bpos, block);
+}
+
+/**
+ * Allocate an indirect block to a map.
+ *
+ * @param fs The file system data.
+ * @param map The map the allocation is for.
+ * @param buffer The buffer the indirect block is accessed by.
+ * @param block The block number of the indirect block allocated.
+ * @param upping True is upping the map to the next indirect level.
+ * @return int The error number (errno). No error if 0.
+ */
+static int
+rtems_rfs_block_map_indirect_alloc (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_buffer_handle* buffer,
+ rtems_rfs_block_no* block,
+ bool upping)
+{
+ rtems_rfs_bitmap_bit new_block;
+ int rc;
+ /*
+ * Save the new block locally because upping can have *block pointing to the
+ * slots which are cleared when upping.
+ */
+ rc = rtems_rfs_group_bitmap_alloc (fs, map->last_map_block, false, &new_block);
+ if (rc > 0)
+ return rc;
+ rc = rtems_rfs_buffer_handle_request (fs, buffer, new_block, false);
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, new_block);
+ return rc;
+ }
+ memset (rtems_rfs_buffer_data (buffer), 0xff, rtems_rfs_fs_block_size (fs));
+ if (upping)
+ {
+ int b;
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_GROW))
+ printf ("rtems-rfs: block-map-grow: upping: block-count=%ld\n",
+ map->size.count);
+ for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
+ rtems_rfs_block_set_number (buffer, b, map->blocks[b]);
+ memset (map->blocks, 0, sizeof (map->blocks));
+ }
+ rtems_rfs_buffer_mark_dirty (buffer);
+ *block = new_block;
+ map->last_map_block = new_block;
+ return 0;
+}
+
+int
+rtems_rfs_block_map_grow (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ size_t blocks,
+ rtems_rfs_block_no* new_block)
+{
+ int b;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_GROW))
+ printf ("rtems-rfs: block-map-grow: entry: blocks=%ld count=%lu\n",
+ blocks, map->size.count);
+
+ if ((map->size.count + blocks) >= rtems_rfs_fs_max_block_map_blocks (fs))
+ return EFBIG;
+
+ /*
+ * Allocate a block at a time. The buffer handles hold the blocks so adding
+ * this way does not thrash the cache with lots of requests.
+ */
+ for (b = 0; b < blocks; b++)
+ {
+ rtems_rfs_bitmap_bit block;
+ int rc;
+
+ /*
+ * Allocate the block. If an indirect block is needed and cannot be
+ * allocated free this block.
+ */
+
+ rc = rtems_rfs_group_bitmap_alloc (fs, map->last_data_block,
+ false, &block);
+ if (rc > 0)
+ return rc;
+
+ if (map->size.count < RTEMS_RFS_INODE_BLOCKS)
+ map->blocks[map->size.count] = block;
+ else
+ {
+ /*
+ * Single indirect access is occuring. It could still be doubly indirect.
+ */
+ rtems_rfs_block_no direct;
+ rtems_rfs_block_no singly;
+
+ direct = map->size.count % fs->blocks_per_block;
+ singly = map->size.count / fs->blocks_per_block;
+
+ if (map->size.count < fs->block_map_singly_blocks)
+ {
+ /*
+ * Singly indirect tables are being used. Allocate a new block for a
+ * mapping table if direct is 0 or we are moving up (upping). If upping
+ * move the direct blocks into the table and if not this is the first
+ * entry of a new block.
+ */
+ if ((direct == 0) ||
+ ((singly == 0) && (direct == RTEMS_RFS_INODE_BLOCKS)))
+ {
+ /*
+ * Upping is when we move from direct to singly indirect.
+ */
+ bool upping;
+ upping = map->size.count == RTEMS_RFS_INODE_BLOCKS;
+ rc = rtems_rfs_block_map_indirect_alloc (fs, map,
+ &map->singly_buffer,
+ &map->blocks[singly],
+ upping);
+ }
+ else
+ {
+ rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
+ map->blocks[singly], true);
+ }
+
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, block);
+ return rc;
+ }
+ }
+ else
+ {
+ /*
+ * Doubly indirect tables are being used.
+ */
+ rtems_rfs_block_no doubly;
+ rtems_rfs_block_no singly_block;
+
+ doubly = singly / fs->blocks_per_block;
+ singly %= fs->blocks_per_block;
+
+ /*
+ * Allocate a new block for a singly indirect table if direct is 0 as
+ * it is the first entry of a new block. We may also need to allocate a
+ * doubly indirect block as well. Both always occur when direct is 0
+ * and the doubly indirect block when singly is 0.
+ */
+ if (direct == 0)
+ {
+ rc = rtems_rfs_block_map_indirect_alloc (fs, map,
+ &map->singly_buffer,
+ &singly_block,
+ false);
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, block);
+ return rc;
+ }
+
+ /*
+ * Allocate a new block for a doubly indirect table if singly is 0 as
+ * it is the first entry of a new singly indirect block.
+ */
+ if ((singly == 0) ||
+ ((doubly == 0) && (singly == RTEMS_RFS_INODE_BLOCKS)))
+ {
+ bool upping;
+ upping = map->size.count == fs->block_map_singly_blocks;
+ rc = rtems_rfs_block_map_indirect_alloc (fs, map,
+ &map->doubly_buffer,
+ &map->blocks[doubly],
+ upping);
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, singly_block);
+ rtems_rfs_group_bitmap_free (fs, false, block);
+ return rc;
+ }
+ }
+ else
+ {
+ rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer,
+ map->blocks[doubly], true);
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, singly_block);
+ rtems_rfs_group_bitmap_free (fs, false, block);
+ return rc;
+ }
+ }
+
+ rtems_rfs_block_set_number (&map->doubly_buffer,
+ singly,
+ singly_block);
+ }
+ else
+ {
+ rc = rtems_rfs_buffer_handle_request (fs,
+ &map->doubly_buffer,
+ map->blocks[doubly],
+ true);
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, block);
+ return rc;
+ }
+
+ singly_block = rtems_rfs_block_get_number (&map->doubly_buffer,
+ singly);
+
+ rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
+ singly_block, true);
+ if (rc > 0)
+ {
+ rtems_rfs_group_bitmap_free (fs, false, block);
+ return rc;
+ }
+ }
+ }
+
+ rtems_rfs_block_set_number (&map->singly_buffer, direct, block);
+ }
+
+ map->size.count++;
+ map->size.offset = 0;
+
+ if (b == 0)
+ *new_block = block;
+ map->last_data_block = block;
+ map->dirty = true;
+ }
+
+ return 0;
+}
+
+/**
+ * Shrink an indirect block.
+ *
+ * @param fs The file system data.
+ * @param map The map the allocation is for.
+ * @param buffer The buffer the indirect block is accessed by.
+ * @param indirect The index index in the inode's block table.
+ * @param index The index in the indirect table of the block.
+ * @return int The error number (errno). No error if 0.
+ */
+static int
+rtems_rfs_block_map_indirect_shrink (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_buffer_handle* buffer,
+ rtems_rfs_block_no indirect,
+ rtems_rfs_block_no index)
+{
+ int rc = 0;
+
+ /*
+ * If this is the first block in the indirect table (index == 0), ie the last
+ * block to be freed and the indirect block is now also free, or we have only
+ * one indirect table and we can fit the remaining blocks into the inode,
+ * then either move to the next indirect block or move the remaining blocks
+ * into the inode and free the indirect table's block.
+ */
+ if ((index == 0) ||
+ ((indirect == 0) && (index == RTEMS_RFS_INODE_BLOCKS)))
+ {
+ rtems_rfs_block_no block_to_free = map->blocks[indirect];
+
+ if ((indirect == 0) && (index == RTEMS_RFS_INODE_BLOCKS))
+ {
+ /*
+ * Move to direct inode access.
+ */
+ int b;
+ for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
+ map->blocks[b] = rtems_rfs_block_get_number (buffer, b);
+ }
+ else
+ {
+ /*
+ * One less singly indirect block in the inode.
+ */
+ map->blocks[indirect] = 0;
+ }
+
+ rc = rtems_rfs_group_bitmap_free (fs, false, block_to_free);
+ if (rc > 0)
+ return rc;
+
+ map->last_map_block = block_to_free;
+ }
+
+ return rc;
+}
+
+int
+rtems_rfs_block_map_shrink (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ size_t blocks)
+{
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BLOCK_MAP_SHRINK))
+ printf ("rtems-rfs: block-map-shrink: entry: blocks=%ld count=%lu\n",
+ blocks, map->size.count);
+
+ if (map->size.count == 0)
+ return 0;
+
+ if (blocks > map->size.count)
+ blocks = map->size.count;
+
+ while (blocks)
+ {
+ rtems_rfs_block_no block;
+ rtems_rfs_block_no block_to_free;
+ int rc;
+
+ block = map->size.count - 1;
+
+ if (block < RTEMS_RFS_INODE_BLOCKS)
+ {
+ /*
+ * We have less than RTEMS_RFS_INODE_BLOCKS so they are held in the
+ * inode.
+ */
+ block_to_free = map->blocks[block];
+ map->blocks[block] = 0;
+ }
+ else
+ {
+ /*
+ * Single indirect access is occuring. It could still be doubly indirect.
+ *
+ * The 'direct' variable is the offset in to the indirect table of
+ * blocks, and 'singly' is the inode block index of the singly indirect
+ * table of block numbers.
+ */
+ rtems_rfs_block_no direct;
+ rtems_rfs_block_no singly;
+
+ direct = block % fs->blocks_per_block;
+ singly = block / fs->blocks_per_block;
+
+ if (block < fs->block_map_singly_blocks)
+ {
+ /*
+ * Request the indirect block and then obtain the block number from the
+ * indirect block.
+ */
+ rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
+ map->blocks[singly], true);
+ if (rc > 0)
+ return rc;
+
+ block_to_free = rtems_rfs_block_get_number (&map->singly_buffer,
+ direct);
+
+ rc = rtems_rfs_block_map_indirect_shrink (fs, map, &map->singly_buffer,
+ singly, direct);
+ if (rc)
+ return rc;
+ }
+ else if (block < fs->block_map_doubly_blocks)
+ {
+ /*
+ * Doubly indirect tables are being used. The 'doubly' variable is the
+ * index in to the inode's block table and points to a singly indirect
+ * table of block numbers. The 'doubly_singly' variable is the index
+ * into the doubly indirect table pointing to the singly indirect table
+ * of block numbers that form the map. This is used later to determine
+ * if the current doubly indirect table needs to be freed. The 'direct'
+ * value is still valid for doubly indirect tables.
+ */
+ rtems_rfs_block_no doubly;
+ rtems_rfs_block_no doubly_singly;
+
+ doubly = singly / fs->blocks_per_block;
+ doubly_singly = singly % fs->blocks_per_block;
+
+ rc = rtems_rfs_buffer_handle_request (fs, &map->doubly_buffer,
+ map->blocks[doubly], true);
+ if (rc > 0)
+ return rc;
+
+ singly = rtems_rfs_block_get_number (&map->doubly_buffer,
+ doubly_singly);
+
+ /*
+ * Read the singly indirect table and get the block number.
+ */
+ rc = rtems_rfs_buffer_handle_request (fs, &map->singly_buffer,
+ singly, true);
+ if (rc > 0)
+ return rc;
+
+ block_to_free = rtems_rfs_block_get_number (&map->singly_buffer,
+ direct);
+
+ if (direct == 0)
+ {
+ rc = rtems_rfs_group_bitmap_free (fs, false, singly);
+ if (rc > 0)
+ return rc;
+
+ map->last_map_block = singly;
+
+ rc = rtems_rfs_block_map_indirect_shrink (fs, map, &map->doubly_buffer,
+ doubly, doubly_singly);
+ if (rc)
+ return rc;
+ }
+ }
+ else
+ {
+ rc = EIO;
+ break;
+ }
+ }
+ rc = rtems_rfs_group_bitmap_free (fs, false, block_to_free);
+ if (rc > 0)
+ return rc;
+ map->size.count--;
+ map->size.offset = 0;
+ map->last_data_block = block_to_free;
+ map->dirty = true;
+ blocks--;
+ }
+
+ if (map->size.count == 0)
+ {
+ map->last_map_block = 0;
+ map->last_data_block = 0;
+ }
+
+ /*
+ * Keep the position inside the map.
+ */
+ if (rtems_rfs_block_pos_past_end (&map->bpos, &map->size))
+ rtems_rfs_block_size_get_bpos (&map->size, &map->bpos);
+
+ return 0;
+}
+
+int
+rtems_rfs_block_map_free_all (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map)
+{
+ return rtems_rfs_block_map_shrink (fs, map, map->size.count);
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-block.h b/cpukit/libfs/src/rfs/rtems-rfs-block.h
new file mode 100644
index 0000000000..a7ae8e3974
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-block.h
@@ -0,0 +1,302 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Block Management.
+ *
+ * These functions manage the blocks used in the file system.
+ */
+
+#if !defined (_RTEMS_RFS_BLOCK_H_)
+#define _RTEMS_RFS_BLOCK_H_
+
+#include <rtems/rfs/rtems-rfs-block-pos.h>
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+
+/**
+ * Get a block number in the media format and return it in the host format.
+ *
+ * @param _h The buffer handle of the block.
+ * @param _b The block number index.
+ * @return uint32_t The block number.
+ */
+#define rtems_rfs_block_get_number(_h, _b) \
+ ((rtems_rfs_block_no) \
+ (rtems_rfs_read_u32 (rtems_rfs_buffer_data (_h) + \
+ ((_b) * sizeof (rtems_rfs_block_no)))))
+
+/**
+ * Set a block number in the media format given a number in the host format.
+ *
+ * @param _h The buffer handle of the block.
+ * @param _b The block number index, ie the number of block number not the
+ * buffer offset.
+ * @param _n The block number.
+ */
+#define rtems_rfs_block_set_number(_h, _b, _n) \
+ do { \
+ rtems_rfs_write_u32 (rtems_rfs_buffer_data (_h) + \
+ ((_b) * sizeof (rtems_rfs_block_no)), (_n)); \
+ rtems_rfs_buffer_mark_dirty (_h); \
+ } while (0)
+
+/**
+ * A block map manges the block lists that originate from an inode. The inode
+ * contains a number of block numbers. A block map takes those block numbers
+ * and manages them.
+ *
+ * The blocks cannot have all ones as a block number nor block 0. The block map
+ * is series of block numbers in a blocks. The size of the map determines the
+ * way the block numbers are stored. The map uses the following:
+ *
+ * @li @e Direct Access,
+ * @li @e Single Indirect Access, and
+ * @li @e Double Indirect Access.
+ *
+ * Direct access has the blocks numbers in the inode slots. The Single Indirect
+ * Access has block numbers in the inode slots that pointer to a table of block
+ * numbers that point to data blocks. The Double Indirect Access has block
+ * numbers in the inode that point to Single Indirect block tables.
+ *
+ * The inode can hold a number of Direct, Single Indirect, and Double Indirect
+ * block tables. The move from Direct to Single occurs then the block count in
+ * the map is above the number of slots in the inode. The move from Single to
+ * Double occurs when the map block count is greated than the block numbers per
+ * block multipled by the slots in the inode. The move from Single to Double
+ * occurs when the map block count is over the block numbers per block squared
+ * multipled by the number of slots in the inode.
+ *
+ * The block map can managed files of the follow size verses block size with 5
+ * inode slots:
+ *
+ * @li 41,943,040 bytes for a 512 byte block size,
+ * @li 335,544,320 bytes for a 1024 byte block size,
+ * @li 2,684,354,560 bytes for a 2048 byte block size, and
+ * @li 21,474,836,480 bytes for a 4096 byte block size.
+ */
+typedef struct rtems_rfs_block_map_t
+{
+ /**
+ * Is the map dirty ?
+ */
+ bool dirty;
+
+ /**
+ * The inode this map is attached to.
+ */
+ rtems_rfs_inode_handle* inode;
+
+ /**
+ * The size of the map.
+ */
+ rtems_rfs_block_size size;
+
+ /**
+ * The block map position. Used to navigate the map when seeking. The find
+ * call is to a position in the file/directory and is a block number plus
+ * offset. The block find only needs to locate a block and not worry about
+ * the offset while a seek can be less than a block size yet move across a
+ * block boundary. Therefore the position a block map has to maintain must
+ * include the offset so seeks work.
+ */
+ rtems_rfs_block_pos bpos;
+
+ /**
+ * The last map block allocated. This is used as the goal when allocating a
+ * new map block.
+ */
+ rtems_rfs_block_no last_map_block;
+
+ /**
+ * The last data block allocated. This is used as the goal when allocating a
+ * new data block.
+ */
+ rtems_rfs_block_no last_data_block;
+
+ /**
+ * The block map.
+ */
+ uint32_t blocks[RTEMS_RFS_INODE_BLOCKS];
+
+ /**
+ * Singly Buffer handle.
+ */
+ rtems_rfs_buffer_handle singly_buffer;
+
+ /**
+ * Doubly Buffer handle.
+ */
+ rtems_rfs_buffer_handle doubly_buffer;
+
+} rtems_rfs_block_map;
+
+/**
+ * Is the map dirty ?
+ */
+#define rtems_rfs_block_map_is_dirty(_m) ((_m)->dirty)
+
+/**
+ * Return the block count in the map.
+ */
+#define rtems_rfs_block_map_count(_m) ((_m)->size.count)
+
+/**
+ * Return the map's size element.
+ */
+#define rtems_rfs_block_map_size(_m) (&((_m)->size))
+
+/**
+ * Return the size offset for the map.
+ */
+#define rtems_rfs_block_map_size_offset(_m) ((_m)->size.offset)
+
+/**
+ * Set the size offset for the map.
+ */
+#define rtems_rfs_block_map_set_size_offset(_m, _o) ((_m)->size.offset = (_o))
+
+/**
+ * Are we at the last block in the map ?
+ */
+#define rtems_rfs_block_map_last(_m) \
+ rtems_rfs_block_pos_last_block (&(_m)->bpos, &(_m)->size)
+
+/**
+ * Is the position past the end of the block ?
+ */
+#define rtems_rfs_block_map_past_end(_m, _p) \
+ rtems_rfs_block_pos_past_end (_p, &(_m)->size)
+
+/**
+ * Return the current position in the map.
+ */
+#define rtems_rfs_block_map_pos(_f, _m) \
+ rtems_rfs_block_get_pos (_f, &(_m)->bpos)
+
+/**
+ * Return the map's current block number.
+ */
+#define rtems_rfs_block_map_block(_m) ((_m)->bpos.bno)
+
+/**
+ * Return the map's current block offset.
+ */
+#define rtems_rfs_block_map_block_offset(_m) ((_m)->bpos.boff)
+
+/**
+ * Open a block map. The block map data in the inode is copied into the
+ * map. The buffer handles are opened. The block position is set to the start
+ * so a seek of offset 0 will return the first block.
+ *
+ * @param fs The file system data.
+ * @prarm inode The inode the map belongs to.
+ * @param map The map that is opened.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_open (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* inode,
+ rtems_rfs_block_map* map);
+
+/**
+ * Close the map. The buffer handles are closed and any help buffers are
+ * released.
+ *
+ * @param fs The file system data.
+ * @param map The map that is opened.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_close (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map);
+
+/**
+ * Find a block number in the map from the position provided.
+ *
+ * @param fs The file system data.
+ * @param map The map to search.
+ * @param bpos The block position to find.
+ * @param block Pointer to place the block in when found.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_find (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_block_pos* bpos,
+ rtems_rfs_buffer_block* block);
+
+/**
+ * Seek around the map.
+ *
+ * @param fs The file system data.
+ * @param map The map to search.
+ * @param offset The distance to seek. It is signed.
+ * @param block Pointer to place the block in when found.
+ * @retval ENXIO Failed to seek because it is outside the block map.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_seek (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_pos_rel offset,
+ rtems_rfs_buffer_block* block);
+
+/**
+ * Seek to the next block.
+ *
+ * @param fs The file system data.
+ * @param map The map to search.
+ * @param block Pointer to place the block in when found.
+ * @retval ENXIO Failed to seek because it is outside the block map.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_next_block (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ rtems_rfs_buffer_block* block);
+
+/**
+ * Grow the block map by the specified number of blocks.
+ *
+ * @param fs The file system data.
+ * @param map Pointer to the open map to grow.
+ * @param blocks The number of blocks to grow the map by.
+ * @param new_block The first of the blocks allocated to the map.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_grow (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ size_t blocks,
+ rtems_rfs_block_no* new_block);
+
+/**
+ * Grow the block map by the specified number of blocks.
+ *
+ * @param fs The file system data.
+ * @param map Pointer to the open map to shrink.
+ * @param blocks The number of blocks to shrink the map by. If more than the
+ * number of blocks the map is emptied.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_shrink (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map,
+ size_t blocks);
+
+/**
+ * Free all blocks in the map.
+ *
+ * @param fs The file system data.
+ * @param map Pointer to the open map to free all blocks from.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_block_map_free_all (rtems_rfs_file_system* fs,
+ rtems_rfs_block_map* map);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-buffer-bdbuf.c b/cpukit/libfs/src/rfs/rtems-rfs-buffer-bdbuf.c
new file mode 100644
index 0000000000..bed5ff8c8e
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-buffer-bdbuf.c
@@ -0,0 +1,87 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Buffer Routines for the RTEMS libblock BD buffer cache.
+ *
+ */
+
+#include <errno.h>
+
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+
+#if RTEMS_RFS_USE_LIBBLOCK
+
+/**
+ * Show errors.
+ */
+#define RTEMS_RFS_BUFFER_ERRORS 0
+
+int
+rtems_rfs_buffer_bdbuf_request (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_block block,
+ bool read,
+ rtems_rfs_buffer** buffer)
+{
+ rtems_status_code sc;
+ int rc = 0;
+
+ if (read)
+ sc = rtems_bdbuf_read (rtems_rfs_fs_device (fs), block, buffer);
+ else
+ sc = rtems_bdbuf_get (rtems_rfs_fs_device (fs), block, buffer);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+#if RTEMS_RFS_BUFFER_ERRORS
+ printf ("rtems-rfs: buffer-bdbuf-request: block=%lu: bdbuf-%s: %d: %s\n",
+ block, read ? "read" : "get", sc, rtems_status_text (sc));
+#endif
+ rc = EIO;
+ }
+
+ return rc;
+}
+
+int
+rtems_rfs_buffer_bdbuf_release (rtems_rfs_buffer* buffer,
+ bool modified)
+{
+ rtems_status_code sc;
+ int rc = 0;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_RELEASE))
+ printf ("rtems-rfs: bdbuf-release: block=%lu bdbuf=%lu %s\n",
+ (rtems_rfs_buffer_block) buffer->user,
+ buffer->block, modified ? "(modified)" : "");
+
+ if (modified)
+ sc = rtems_bdbuf_release_modified (buffer);
+ else
+ sc = rtems_bdbuf_release (buffer);
+
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+#if RTEMS_RFS_BUFFER_ERRORS
+ printf ("rtems-rfs: buffer-release: bdbuf-%s: %s(%d)\n",
+ modified ? "modified" : "not-modified",
+ rtems_status_text (sc), sc);
+#endif
+ rc = EIO;
+ }
+
+ return rc;
+}
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-buffer-devio.c b/cpukit/libfs/src/rfs/rtems-rfs-buffer-devio.c
new file mode 100644
index 0000000000..157fc0305a
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-buffer-devio.c
@@ -0,0 +1,57 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Buffer Routines.
+ *
+ */
+
+#include <errno.h>
+
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+
+#if !RTEMS_RFS_USE_LIBBLOCK
+
+/**
+ * Show errors.
+ */
+#define RTEMS_RFS_BUFFER_ERRORS 1
+
+int
+rtems_rfs_buffer_deviceio_request (rtems_rfs_buffer_handle* handle,
+ dev_t device,
+ rtems_rfs_buffer_block block,
+ bool read)
+{
+}
+
+int
+rtems_rfs_buffer_deviceio_release (rtems_rfs_buffer_handle* handle,
+ dev_t device)
+{
+}
+
+int
+rtems_rfs_buffer_deviceio_handle_open (rtems_rfs_buffer_handle* handle,
+ dev_t device)
+{
+}
+
+int
+rtems_rfs_buffer_device_handle_close (rtems_rfs_buffer_handle* handle,
+ dev_t device)
+{
+}
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-buffer.c b/cpukit/libfs/src/rfs/rtems-rfs-buffer.c
new file mode 100644
index 0000000000..ee1a7f6bde
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-buffer.c
@@ -0,0 +1,478 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Buffer Routines.
+ *
+ */
+
+#include <errno.h>
+
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+
+/**
+ * Scan the chain for a buffer that matches the block number.
+ *
+ * @param chain The chain to scan.
+ * @param count The number of items on the chain.
+ * @param block The block number to find.
+ * @return rtems_rfs_buffer* The buffer if found else NULL.
+ */
+static rtems_rfs_buffer*
+rtems_rfs_scan_chain (rtems_chain_control* chain,
+ uint32_t* count,
+ rtems_rfs_buffer_block block)
+{
+ rtems_rfs_buffer* buffer;
+ rtems_chain_node* node;
+
+ node = rtems_chain_last (chain);
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
+ printf ("rtems-rfs: buffer-scan: count=%lu, block=%lu: ", *count, block);
+
+ while (!rtems_chain_is_head (chain, node))
+ {
+ buffer = (rtems_rfs_buffer*) node;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
+ printf ("%lu ", (rtems_rfs_buffer_block) buffer->user);
+
+ if (((rtems_rfs_buffer_block) buffer->user) == block)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
+ printf (": found block=%lu\n", (rtems_rfs_buffer_block) buffer->user);
+
+ (*count)--;
+ rtems_chain_extract (node);
+ rtems_chain_set_off_chain (node);
+ return buffer;
+ }
+ node = rtems_chain_previous (node);
+ }
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
+ printf (": not found\n");
+
+ return NULL;
+}
+
+int
+rtems_rfs_buffer_handle_request (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* handle,
+ rtems_rfs_buffer_block block,
+ bool read)
+{
+ int rc;
+
+ /*
+ * If the handle has a buffer release it. This allows a handle to be reused
+ * without needing to close then open it again.
+ */
+ if (rtems_rfs_buffer_handle_has_block (handle))
+ {
+ /*
+ * Treat block 0 as special to handle the loading of the super block.
+ */
+ if (block && (rtems_rfs_buffer_bnum (handle) == block))
+ return 0;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
+ printf ("rtems-rfs: buffer-request: handle has buffer: %lu\n",
+ rtems_rfs_buffer_bnum (handle));
+
+ rc = rtems_rfs_buffer_handle_release (fs, handle);
+ if (rc > 0)
+ return rc;
+ handle->dirty = false;
+ handle->bnum = 0;
+ }
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
+ printf ("rtems-rfs: buffer-request: block=%lu\n", block);
+
+ /*
+ * First check to see if the buffer has already been requested and is
+ * currently attached to a handle. If it is share the access. A buffer could
+ * be shared where different parts of the block have separate functions. An
+ * example is an inode block and the file system needs to handle 2 inodes in
+ * the same block at the same time.
+ */
+ if (fs->buffers_count)
+ {
+ /*
+ * Check the active buffer list for shared buffers.
+ */
+ handle->buffer = rtems_rfs_scan_chain (&fs->buffers,
+ &fs->buffers_count,
+ block);
+ if (rtems_rfs_buffer_handle_has_block (handle) &&
+ rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
+ printf ("rtems-rfs: buffer-request: buffer shared: refs: %d\n",
+ rtems_rfs_buffer_refs (handle) + 1);
+ }
+
+ /*
+ * If the buffer has not been found check the local cache of released
+ * buffers. There are release and released modified lists to preserve the
+ * state.
+ */
+ if (!rtems_rfs_fs_no_local_cache (fs) &&
+ !rtems_rfs_buffer_handle_has_block (handle))
+ {
+ /*
+ * Check the local cache of released buffers.
+ */
+ if (fs->release_count)
+ handle->buffer = rtems_rfs_scan_chain (&fs->release,
+ &fs->release_count,
+ block);
+
+ if (!rtems_rfs_buffer_handle_has_block (handle) &&
+ fs->release_modified_count)
+ {
+ handle->buffer = rtems_rfs_scan_chain (&fs->release_modified,
+ &fs->release_modified_count,
+ block);
+ /*
+ * If we found a buffer retain the dirty buffer state.
+ */
+ if (rtems_rfs_buffer_handle_has_block (handle))
+ rtems_rfs_buffer_mark_dirty (handle);
+ }
+ }
+
+ /*
+ * If not located we request the buffer from the I/O layer.
+ */
+ if (!rtems_rfs_buffer_handle_has_block (handle))
+ {
+ rc = rtems_rfs_buffer_io_request (fs, block, read, &handle->buffer);
+
+ rtems_chain_set_off_chain (rtems_rfs_buffer_link(handle));
+
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
+ printf ("rtems-rfs: buffer-request: block=%lu: bdbuf-%s: %d: %s\n",
+ block, read ? "read" : "get", rc, strerror (rc));
+ return rc;
+ }
+ }
+
+ /*
+ * Increase the reference count of the buffer.
+ */
+ rtems_rfs_buffer_refs_up (handle);
+ rtems_chain_append (&fs->buffers, rtems_rfs_buffer_link (handle));
+ fs->buffers_count++;
+
+ handle->buffer->user = (void*) block;
+ handle->bnum = block;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST))
+ printf ("rtems-rfs: buffer-request: block=%lu bdbuf-%s=%lu refs=%d\n",
+ block, read ? "read" : "get", handle->buffer->block,
+ handle->buffer->references);
+
+ return 0;
+}
+
+int
+rtems_rfs_buffer_handle_release (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* handle)
+{
+ int rc = 0;
+
+ if (rtems_rfs_buffer_handle_has_block (handle))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
+ printf ("rtems-rfs: buffer-release: block=%lu %s refs=%d %s\n",
+ rtems_rfs_buffer_bnum (handle),
+ rtems_rfs_buffer_dirty (handle) ? "(dirty)" : "",
+ rtems_rfs_buffer_refs (handle),
+ rtems_rfs_buffer_refs (handle) == 0 ? "BAD REF COUNT" : "");
+
+ if (rtems_rfs_buffer_refs (handle) > 0)
+ rtems_rfs_buffer_refs_down (handle);
+
+ if (rtems_rfs_buffer_refs (handle) == 0)
+ {
+ rtems_chain_extract (rtems_rfs_buffer_link (handle));
+ fs->buffers_count--;
+
+ if (rtems_rfs_fs_no_local_cache (fs))
+ {
+ handle->buffer->user = (void*) 0;
+ rc = rtems_rfs_buffer_io_release (handle->buffer,
+ rtems_rfs_buffer_dirty (handle));
+ }
+ else
+ {
+ /*
+ * If the total number of held buffers is higher than the configured
+ * value remove a buffer from the queue with the most buffers and
+ * release. The buffers are held on the queues with the newest at the
+ * head.
+ *
+ * This code stops a large series of transactions causing all the
+ * buffers in the cache being held in queues of this file system.
+ */
+ if ((fs->release_count +
+ fs->release_modified_count) >= fs->max_held_buffers)
+ {
+ rtems_rfs_buffer* buffer;
+ bool modified;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE))
+ printf ("rtems-rfs: buffer-release: local cache overflow:" \
+ " %lu\n", fs->release_count + fs->release_modified_count);
+
+ if (fs->release_count > fs->release_modified_count)
+ {
+ buffer = (rtems_rfs_buffer*) rtems_chain_get (&fs->release);
+ fs->release_count--;
+ modified = false;
+ }
+ else
+ {
+ buffer =
+ (rtems_rfs_buffer*) rtems_chain_get (&fs->release_modified);
+ fs->release_modified_count--;
+ modified = true;
+ }
+ buffer->user = (void*) 0;
+ rc = rtems_rfs_buffer_io_release (buffer, modified);
+ }
+
+ if (rtems_rfs_buffer_dirty (handle))
+ {
+ rtems_chain_append (&fs->release_modified,
+ rtems_rfs_buffer_link (handle));
+ fs->release_modified_count++;
+ }
+ else
+ {
+ rtems_chain_append (&fs->release, rtems_rfs_buffer_link (handle));
+ fs->release_count++;
+ }
+ }
+ }
+ handle->buffer = NULL;
+ }
+
+ return rc;
+}
+
+int
+rtems_rfs_buffer_open (const char* name, rtems_rfs_file_system* fs)
+{
+ struct stat st;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
+ printf ("rtems-rfs: buffer-open: opening: %s\n", name);
+
+ if (stat (name, &st) < 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
+ printf ("rtems-rfs: buffer-open: stat '%s' failed: %s\n",
+ name, strerror (errno));
+ return ENOENT;
+ }
+
+#if RTEMS_RFS_USE_LIBBLOCK
+ /*
+ * Is the device a block device ?
+ */
+ if (!S_ISCHR (st.st_mode))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
+ printf ("rtems-rfs: buffer-open: '%s' is not a block device\n", name);
+ return EIO;
+ }
+
+ /*
+ * Check that device is registred as a block device and lock it.
+ */
+ fs->disk = rtems_disk_obtain (st.st_rdev);
+ if (!fs->disk)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
+ printf ("rtems-rfs: buffer-open: cannot obtain the disk\n");
+ return EIO;
+ }
+#else
+ fs->device = open (name, O_RDWR);
+ if (fs->device < 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_OPEN))
+ printf ("rtems-rfs: buffer-open: cannot open file\n");
+ }
+ fs->media_size = st.st_size;
+ strcat (fs->name, name);
+#endif
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
+ printf ("rtems-rfs: buffer-open: blks=%ld, blk-size=%ld\n",
+ rtems_rfs_fs_media_blocks (fs),
+ rtems_rfs_fs_media_block_size (fs));
+
+ return 0;
+}
+
+int
+rtems_rfs_buffer_close (rtems_rfs_file_system* fs)
+{
+ int rc = 0;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
+ printf ("rtems-rfs: buffer-close: closing\n");
+
+ /*
+ * Change the block size to the media device size. It will release and sync
+ * all buffers.
+ */
+ rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_media_block_size (fs));
+
+ if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
+ printf ("rtems-rfs: buffer-close: set media block size failed: %d: %s\n",
+ rc, strerror (rc));
+
+#if RTEMS_RFS_USE_LIBBLOCK
+ rtems_disk_release (fs->disk);
+#else
+ if (close (fs->device) < 0)
+ {
+ rc = errno;
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
+ printf ("rtems-rfs: buffer-close: file close failed: %d: %s\n",
+ rc, strerror (rc));
+ }
+#endif
+
+ return rc;
+}
+
+int
+rtems_rfs_buffer_sync (rtems_rfs_file_system* fs)
+{
+ int result = 0;
+#if RTEMS_RFS_USE_LIBBLOCK
+ rtems_status_code sc;
+#endif
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
+ printf ("rtems-rfs: buffer-sync: syncing\n");
+
+ /*
+ * @todo Split in the separate files for each type.
+ */
+#if RTEMS_RFS_USE_LIBBLOCK
+ sc = rtems_bdbuf_syncdev (rtems_rfs_fs_device (fs));
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SYNC))
+ printf ("rtems-rfs: buffer-sync: device sync failed: %s\n",
+ rtems_status_text (sc));
+ result = EIO;
+ }
+ rtems_disk_release (fs->disk);
+#else
+ if (fsync (fs->device) < 0)
+ {
+ result = errno;
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CLOSE))
+ printf ("rtems-rfs: buffer-sync: file sync failed: %d: %s\n",
+ result, strerror (result));
+ }
+#endif
+ return result;
+}
+
+int
+rtems_rfs_buffer_setblksize (rtems_rfs_file_system* fs, size_t size)
+{
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE))
+ printf ("rtems-rfs: buffer-setblksize: block size: %lu\n", size);
+
+ rc = rtems_rfs_buffers_release (fs);
+ if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE))
+ printf ("rtems-rfs: buffer-setblksize: buffer release failed: %d: %s\n",
+ rc, strerror (rc));
+
+ rc = rtems_rfs_buffer_sync (fs);
+ if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE))
+ printf ("rtems-rfs: buffer-setblksize: device sync failed: %d: %s\n",
+ rc, strerror (rc));
+
+#if RTEMS_RFS_USE_LIBBLOCK
+ rc = fs->disk->ioctl (fs->disk, RTEMS_BLKIO_SETBLKSIZE, &size);
+ if (rc < 0)
+ rc = errno;
+#endif
+ return rc;
+}
+
+static int
+rtems_rfs_release_chain (rtems_chain_control* chain,
+ uint32_t* count,
+ bool modified)
+{
+ rtems_rfs_buffer* buffer;
+ int rrc = 0;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_CHAINS))
+ printf ("rtems-rfs: release-chain: count=%lu\n", *count);
+
+ while (!rtems_chain_is_empty (chain))
+ {
+ buffer = (rtems_rfs_buffer*) rtems_chain_get (chain);
+ (*count)--;
+
+ buffer->user = (void*) 0;
+
+ rc = rtems_rfs_buffer_io_release (buffer, modified);
+ if ((rc > 0) && (rrc == 0))
+ rrc = rc;
+ }
+ return rrc;
+}
+
+int
+rtems_rfs_buffers_release (rtems_rfs_file_system* fs)
+{
+ int rrc = 0;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_BUFFER_RELEASE))
+ printf ("rtems-rfs: buffers-release: active:%lu " \
+ "release:%lu release-modified:%lu\n",
+ fs->buffers_count, fs->release_count, fs->release_modified_count);
+
+ rc = rtems_rfs_release_chain (&fs->release,
+ &fs->release_count,
+ false);
+ if ((rc > 0) && (rrc == 0))
+ rrc = rc;
+ rc = rtems_rfs_release_chain (&fs->release_modified,
+ &fs->release_modified_count,
+ true);
+ if ((rc > 0) && (rrc == 0))
+ rrc = rc;
+
+ return rrc;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-buffer.h b/cpukit/libfs/src/rfs/rtems-rfs-buffer.h
new file mode 100644
index 0000000000..480bce360d
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-buffer.h
@@ -0,0 +1,262 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Buffer Management.
+ *
+ * These functions map blocks to the media interface layers.
+ */
+
+#if !defined (_RTEMS_RFS_BUFFER_H_)
+#define _RTEMS_RFS_BUFFER_H_
+
+#include <errno.h>
+
+#include <rtems/rfs/rtems-rfs-file-system-fwd.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+/**
+ * Define the method used to interface to the buffers. It can be libblock or
+ * device I/O. The libblock interface is to the RTEMS cache and block devices
+ * and device I/O accesses the media via a device file handle.
+ */
+#if defined (__rtems__)
+#define RTEMS_RFS_USE_LIBBLOCK 1
+#endif
+
+/**
+ * The RTEMS RFS I/O Layering.
+ */
+#if RTEMS_RFS_USE_LIBBLOCK
+#include <rtems/bdbuf.h>
+#include <rtems/error.h>
+
+typedef rtems_blkdev_bnum rtems_rfs_buffer_block;
+typedef rtems_bdbuf_buffer rtems_rfs_buffer;
+#define rtems_rfs_buffer_io_request rtems_rfs_buffer_bdbuf_request
+#define rtems_rfs_buffer_io_release rtems_rfs_buffer_bdbuf_release
+
+/**
+ * Request a buffer from the RTEMS libblock BD buffer cache.
+ */
+int rtems_rfs_buffer_bdbuf_request (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_block block,
+ bool read,
+ rtems_rfs_buffer** buffer);
+/**
+ * Release a buffer to the RTEMS libblock BD buffer cache.
+ */
+int rtems_rfs_buffer_bdbuf_release (rtems_rfs_buffer* handle,
+ bool modified);
+#else /* Device I/O */
+typedef uint32_t rtems_rfs_buffer_block;
+typedef struct rtems_rfs_buffer_t
+{
+ rtems_chain_node link;
+ rtems_rfs_buffer_block user;
+ void* buffer;
+ size_t size;
+ uint32_t references;
+} rtems_rfs_buffer;
+#define rtems_rfs_buffer_io_request rtems_rfs_buffer_devceio_request
+#define rtems_rfs_buffer_io_release rtems_rfs_uffer_deviceio_release
+
+/**
+ * Request a buffer from the device I/O.
+ */
+int rtems_rfs_buffer_deviceio_request (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_block block,
+ bool read,
+ rtems_rfs_buffer* buffer);
+/**
+ * Release a buffer to the RTEMS libblock BD buffer cache.
+ */
+int rtems_rfs_buffer_deviceio_release (rtems_rfs_buffer* handle,
+ bool modified);
+#endif
+
+/**
+ * RFS Buffer handle.
+ */
+typedef struct rtems_rfs_buffer_handle_t
+{
+ /**
+ * Has the buffer been modifed?
+ */
+ bool dirty;
+
+ /**
+ * Block number. The lower layer block number may be absolute and we maybe
+ * relative to an offset in the disk so hold locally.
+ */
+ rtems_rfs_buffer_block bnum;
+
+ /**
+ * Reference the buffer descriptor.
+ */
+ rtems_rfs_buffer* buffer;
+
+} rtems_rfs_buffer_handle;
+
+/**
+ * The buffer linkage.
+ */
+#define rtems_rfs_buffer_link(_h) (&(_h)->buffer->link)
+
+/**
+ * Return the start of the data area of the buffer given a handle.
+ */
+#define rtems_rfs_buffer_data(_h) ((void*)((_h)->buffer->buffer))
+
+/**
+ * Return the size of the buffer given a handle.
+ */
+#define rtems_rfs_buffer_size(_h) ((_h)->buffer->size)
+
+/**
+ * Return the block number.
+ */
+#define rtems_rfs_buffer_bnum(_h) ((_h)->bnum)
+
+/**
+ * Return the buffer dirty status.
+ */
+#define rtems_rfs_buffer_dirty(_h) ((_h)->dirty)
+
+/**
+ * Does the handle have a valid block attached ?
+ */
+#define rtems_rfs_buffer_handle_has_block(_h) ((_h)->buffer ? true : false)
+
+/**
+ * Mark the buffer as dirty.
+ */
+#define rtems_rfs_buffer_mark_dirty(_h) ((_h)->dirty = true)
+
+/**
+ * Return the reference count.
+ */
+#define rtems_rfs_buffer_refs(_h) ((_h)->buffer->references)
+
+/**
+ * Increment the reference count.
+ */
+#define rtems_rfs_buffer_refs_up(_h) ((_h)->buffer->references += 1)
+
+/**
+ * Decrement the reference count.
+ */
+#define rtems_rfs_buffer_refs_down(_h) ((_h)->buffer->references -= 1)
+
+/**
+ * Request a buffer. The buffer can be filled with data from the media (read ==
+ * true) or you can request a buffer to fill with data.
+ *
+ * @param fs The file system data.
+ * @param handle The handle the requested buffer is attached to.
+ * @param block The block number.
+ * @param read Read the data from the disk.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffer_handle_request (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* handle,
+ rtems_rfs_buffer_block block,
+ bool read);
+
+/**
+ * Release a buffer. If the buffer is dirty the buffer is written to disk. The
+ * result does not indicate if the data was successfully written to the disk as
+ * this operation may be performed in asynchronously to this release.
+ *
+ * @param fs The file system data.
+ * @param handle The handle the requested buffer is attached to.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffer_handle_release (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* handle);
+
+/**
+ * Open a handle.
+ *
+ * @param fs The file system data.
+ * @param handle The buffer handle to open.
+ * @return int The error number (errno). No error if 0.
+ */
+static inline int
+rtems_rfs_buffer_handle_open (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* handle)
+{
+ handle->dirty = false;
+ handle->bnum = 0;
+ handle->buffer = NULL;
+ return 0;
+}
+
+/**
+ * Close a handle.
+ *
+ * @param fs The file system data.
+ * @param handle The buffer handle to close.
+ * @return int The error number (errno). No error if 0.
+ */
+static inline int
+rtems_rfs_buffer_handle_close (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_handle* handle)
+{
+ rtems_rfs_buffer_handle_release (fs, handle);
+ return 0;
+}
+
+/**
+ * Open the buffer interface.
+ *
+ * @param name The device name to the media.
+ * @param fs Pointer to the file system data.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffer_open (const char* name, rtems_rfs_file_system* fs);
+
+/**
+ * Close the buffer interface.
+ *
+ * @param fs Pointer to the file system data.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffer_close (rtems_rfs_file_system* fs);
+
+/**
+ * Sync all buffers to the media.
+ *
+ * @param fs Pointer to the file system data.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffer_sync (rtems_rfs_file_system* fs);
+
+/**
+ * Set the block size of the device.
+ *
+ * @param fs Pointer to the file system data.
+ * @param size The new block size.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffer_setblksize (rtems_rfs_file_system* fs, size_t size);
+
+/**
+ * Release any chained buffers.
+ *
+ * @param fs The file system data.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_buffers_release (rtems_rfs_file_system* fs);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-data.h b/cpukit/libfs/src/rfs/rtems-rfs-data.h
new file mode 100644
index 0000000000..67e820faac
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-data.h
@@ -0,0 +1,78 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Data.
+ *
+ * Access data in the correct byte order for the specific target we are running
+ * on.
+ *
+ * @todo Make direct access on matching byte ordered targets.
+ */
+
+#if !defined (_RTEMS_RFS_DATA_H_)
+#define _RTEMS_RFS_DATA_H_
+
+#include <stdint.h>
+
+/**
+ * Helper function to make sure we have a byte pointer.
+ */
+#define rtems_rfs_data_ptr(_d) ((uint8_t*)(_d))
+
+/**
+ * RFS Read Unsigned 8bit Integer
+ */
+#define rtems_rfs_read_u8(_d) \
+ (*rtems_rfs_data_ptr (_d))
+
+/**
+ * RFS Read Unsigned 16bit Integer
+ */
+#define rtems_rfs_read_u16(_d) \
+ ((rtems_rfs_data_ptr (_d)[0] << 8) | (rtems_rfs_data_ptr (_d)[1]))
+
+/**
+ * RFS Read Unsigned 32bit Integer
+ */
+#define rtems_rfs_read_u32(_d) \
+ ((rtems_rfs_data_ptr (_d)[0] << 24) | (rtems_rfs_data_ptr (_d)[1] << 16) | \
+ (rtems_rfs_data_ptr (_d)[2] << 8) | (rtems_rfs_data_ptr (_d)[3]))
+
+/**
+ * RFS Write Unsigned 8bit Integer
+ */
+#define rtems_rfs_write_u8(_d, _v) \
+ (*rtems_rfs_data_ptr (_d) = (uint8_t)(_v))
+
+/**
+ * RFS Write Unsigned 16bit Integer
+ */
+#define rtems_rfs_write_u16(_d, _v) \
+ do { \
+ rtems_rfs_data_ptr (_d)[0] = (uint8_t)((_v) >> 8); \
+ rtems_rfs_data_ptr (_d)[1] = (uint8_t)((_v)); \
+ } while (0)
+
+/**
+ * RFS Write Unsigned 32bit Integer
+ */
+#define rtems_rfs_write_u32(_d, _v) \
+ do { \
+ rtems_rfs_data_ptr (_d)[0] = (uint8_t)((_v) >> 24); \
+ rtems_rfs_data_ptr (_d)[1] = (uint8_t)((_v) >> 16); \
+ rtems_rfs_data_ptr (_d)[2] = (uint8_t)((_v) >> 8); \
+ rtems_rfs_data_ptr (_d)[3] = (uint8_t)((_v)); \
+ } while (0)
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-dir-hash.c b/cpukit/libfs/src/rfs/rtems-rfs-dir-hash.c
new file mode 100644
index 0000000000..791883390e
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-dir-hash.c
@@ -0,0 +1,337 @@
+/*
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Directory Hash function.
+ */
+
+#include <rtems/rfs/rtems-rfs-dir-hash.h>
+
+#ifdef __rtems__
+# include <machine/endian.h> /* attempt to define endianness */
+#endif
+#ifdef linux
+# include <endian.h> /* attempt to define endianness */
+#endif
+
+/*
+ * My best guess at if you are big-endian or little-endian. This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+ __BYTE_ORDER == __LITTLE_ENDIAN) || \
+ (defined(i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+ __BYTE_ORDER == __BIG_ENDIAN) || \
+ (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+ -------------------------------------------------------------------------------
+ mix -- mix 3 32-bit values reversibly.
+
+ This is reversible, so any information in (a,b,c) before mix() is still in
+ (a,b,c) after mix().
+
+ If four pairs of (a,b,c) inputs are run through mix(), or through mix() in
+ reverse, there are at least 32 bits of the output that are sometimes the same
+ for one pair and different for another pair. This was tested for:
+
+ * pairs that differed by one bit, by two bits, in any combination of top bits
+ of (a,b,c), or in any combination of bottom bits of (a,b,c).
+
+ * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the
+ output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly
+ produced by subtraction) look like a single 1-bit difference.
+
+ * the base values were pseudorandom, all zero but one bit set, or all zero
+ plus a counter that starts at zero.
+
+ Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that satisfy this
+ are:
+
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+
+ Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing for "differ" defined
+ as + with a one-bit base and a two-bit delta. I used
+ http://burtleburtle.net/bob/hash/avalanche.html to choose the operations,
+ constants, and arrangements of the variables.
+
+ This does not achieve avalanche. There are input bits of (a,b,c) that fail
+ to affect some output bits of (a,b,c), especially of a. The most thoroughly
+ mixed value is c, but it doesn't really even achieve avalanche in c.
+
+ This allows some parallelism. Read-after-writes are good at doubling the
+ number of bits affected, so the goal of mixing pulls in the opposite
+ direction as the goal of parallelism. I did what I could. Rotates seem to
+ cost as much as shifts on every machine I could lay my hands on, and rotates
+ are much kinder to the top and bottom bits, so I used rotates.
+ -------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+ { \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+ }
+
+/*
+ -------------------------------------------------------------------------------
+ final -- final mixing of 3 32-bit values (a,b,c) into c
+
+ Pairs of (a,b,c) values differing in only a few bits will usually produce
+ values of c that look totally different. This was tested for
+
+ * pairs that differed by one bit, by two bits, in any combination of top bits
+ of (a,b,c), or in any combination of bottom bits of (a,b,c).
+
+ * "differ" is defined as +, -, ^, or ~^. For + and -, I transformed the
+ output delta to a Gray code (a^(a>>1)) so a string of 1's (as is commonly
+ produced by subtraction) look like a single 1-bit difference. * the base
+ values were pseudorandom, all zero but one bit set, or all zero plus a
+ counter that starts at zero.
+
+ These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+ and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+ -------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+ { \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+ }
+
+/**
+ * The follow is the documentation from Bob Jenkin's hash function:
+ *
+ * http://burtleburtle.net/bob/hash/doobs.html
+ *
+ * The function hashlittle() has been renamed.
+ *
+ * hashlittle() -- hash a variable-length key into a 32-bit value
+ *
+ * k : the key (the unaligned variable-length array of bytes)
+ * length : the length of the key, counting by bytes
+ * initval : can be any 4-byte value
+ *
+ * Returns a 32-bit value. Every bit of the key affects every bit of the
+ * return value. Two keys differing by one or two bits will have totally
+ * different hash values.
+ *
+ * The best hash table sizes are powers of 2. There is no need to do mod a
+ * prime (mod is sooo slow!). If you need less than 32 bits, use a bitmask.
+ * For example, if you need only 10 bits, do h = (h & hashmask(10)); In which
+ * case, the hash table should have hashsize(10) elements.
+ *
+ * If you are hashing n strings (uint8_t **)k, do it like this: for (i=0, h=0;
+ * i<n; ++i) h = hashlittle( k[i], len[i], h);
+ *
+ * By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+ * code any way you wish, private, educational, or commercial. It's free.
+ *
+ * Use for hash table lookup, or anything where one collision in 2^^32 is
+ * acceptable. Do NOT use for cryptographic purposes.
+*/
+
+#define initval (20010928)
+uint32_t
+rtems_rfs_dir_hash (const void *key, size_t length)
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+ /*const uint8_t *k8;*/
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-dir-hash.h b/cpukit/libfs/src/rfs/rtems-rfs-dir-hash.h
new file mode 100644
index 0000000000..ca761dd0cc
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-dir-hash.h
@@ -0,0 +1,34 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Directory Hash provides a 32bit hash of a string. This is
+ * used to search a directory.
+ */
+
+#if !defined (_RTEMS_RFS_DIR_HASH_H_)
+#define _RTEMS_RFS_DIR_HAS_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+/**
+ * Compute a hash of the key over the length of string.
+ *
+ * @param key The key to calculate the hash of.
+ * @param length The length of the key in bytes.
+ * @return uint32_t The hash.
+ */
+uint32_t rtems_rfs_dir_hash (const void *key, size_t length);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-dir.c b/cpukit/libfs/src/rfs/rtems-rfs-dir.c
new file mode 100644
index 0000000000..8813fb751e
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-dir.c
@@ -0,0 +1,742 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Directory Routines.
+ *
+ * These functions manage blocks in the directory format. A directory entry is
+ * a variable length record in the block. The entry consists of a length, hash
+ * and the string. The length allows the next entry to be located and the hash
+ * allows a simple check to be performed wihtout a string compare. Directory
+ * entries do not span a block and removal of an entry results in the space in
+ * the block being compacted and the spare area being initialised to ones.
+ *
+ * The maximum length can be 1 or 2 bytes depending on the value in the
+ * superblock.
+ */
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+#include <rtems/rfs/rtems-rfs-dir-hash.h>
+
+int
+rtems_rfs_dir_lookup_ino (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* inode,
+ const char* name,
+ int length,
+ rtems_rfs_ino* ino,
+ uint32_t* offset)
+{
+ rtems_rfs_block_map map;
+ rtems_rfs_buffer_handle entries;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ {
+ int c;
+ printf ("rtems-rfs: dir-lookup-ino: lookup ino: root=%ld, path=",
+ inode->ino);
+ for (c = 0; c < length; c++)
+ printf ("%c", name[c]);
+ printf (", len=%d\n", length);
+ }
+
+ *ino = RTEMS_RFS_EMPTY_INO;
+ *offset = 0;
+
+ rc = rtems_rfs_block_map_open (fs, inode, &map);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: map open failed for ino %lu: %d: %s",
+ rtems_rfs_inode_ino (inode), rc, strerror (rc));
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &entries);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: handle open failed for ino %lu: %d: %s",
+ rtems_rfs_inode_ino (inode), rc, strerror (rc));
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+ else
+ {
+ rtems_rfs_block_no block;
+ uint32_t hash;
+
+ /*
+ * Calculate the hash of the look up string.
+ */
+ hash = rtems_rfs_dir_hash (name, length);
+
+ /*
+ * Locate the first block. The map points to the start after open so just
+ * seek 0. If an error the block will be 0.
+ */
+ rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: block map find failed: %d: %s\n",
+ rc, strerror (rc));
+ if (rc == ENXIO)
+ rc = ENOENT;
+ rtems_rfs_buffer_handle_close (fs, &entries);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ while ((rc == 0) && block)
+ {
+ uint8_t* entry;
+
+ rc = rtems_rfs_buffer_handle_request (fs, &entries, block, true);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: block read, ino=%lu block=%ld: %d: %s\n",
+ rtems_rfs_inode_ino (inode), block, rc, strerror (rc));
+ break;
+ }
+
+ /*
+ * Search the block to see if the name matches. A hash of 0xffff or 0x0
+ * means the entry is empty.
+ */
+
+ entry = rtems_rfs_buffer_data (&entries);
+
+ map.bpos.boff = 0;
+
+ while (map.bpos.boff < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
+ {
+ uint32_t ehash;
+ int elength;
+
+ ehash = rtems_rfs_dir_entry_hash (entry);
+ elength = rtems_rfs_dir_entry_length (entry);
+ *ino = rtems_rfs_dir_entry_ino (entry);
+
+ if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
+ break;
+
+ if ((elength <= RTEMS_RFS_DIR_ENTRY_SIZE)
+ || (elength >= rtems_rfs_fs_max_name (fs))
+ || (*ino < RTEMS_RFS_ROOT_INO)
+ || (*ino >= rtems_rfs_fs_inodes (fs)))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: " \
+ "bad length or ino for ino %lu: %u/%ld @ %04lx\n",
+ rtems_rfs_inode_ino (inode), elength, *ino, map.bpos.boff);
+ rc = EIO;
+ break;
+ }
+
+ if (ehash == hash)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_CHECK))
+ printf ("rtems-rfs: dir-lookup-ino: " \
+ "checking entry for ino %ld: off=%04lx length:%d ino:%d\n",
+ rtems_rfs_inode_ino (inode), map.bpos.boff,
+ elength, rtems_rfs_dir_entry_ino (entry));
+
+ if (memcmp (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length) == 0)
+ {
+ *offset = rtems_rfs_block_map_pos (fs, &map);
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO_FOUND))
+ printf ("rtems-rfs: dir-lookup-ino: " \
+ "entry found in ino %lu, ino=%lu offset=%lu\n",
+ rtems_rfs_inode_ino (inode), *ino, *offset);
+
+ rtems_rfs_buffer_handle_close (fs, &entries);
+ rtems_rfs_block_map_close (fs, &map);
+ return 0;
+ }
+ }
+
+ map.bpos.boff += elength;
+ entry += elength;
+ }
+
+ if (rc == 0)
+ {
+ rc = rtems_rfs_block_map_next_block (fs, &map, &block);
+ if ((rc > 0) && (rc != ENXIO))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: " \
+ "block map next block failed in ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (inode), rc, strerror (rc));
+ }
+ if (rc == ENXIO)
+ rc = ENOENT;
+ }
+ }
+
+ if ((rc == 0) && (block == 0))
+ {
+ rc = EIO;
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_LOOKUP_INO))
+ printf ("rtems-rfs: dir-lookup-ino: block is 0 in ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (inode), rc, strerror (rc));
+ }
+ }
+
+ rtems_rfs_buffer_handle_close (fs, &entries);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+}
+
+int
+rtems_rfs_dir_add_entry (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir,
+ const char* name,
+ size_t length,
+ rtems_rfs_ino ino)
+{
+ rtems_rfs_block_map map;
+ rtems_rfs_block_pos bpos;
+ rtems_rfs_buffer_handle buffer;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
+ {
+ int c;
+ printf ("rtems-rfs: dir-add-entry: dir=%ld, name=",
+ rtems_rfs_inode_ino (dir));
+ for (c = 0; c < length; c++)
+ printf ("%c", name[c]);
+ printf (", len=%ld\n", length);
+ }
+
+ rc = rtems_rfs_block_map_open (fs, dir, &map);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ /*
+ * Search the map from the beginning to find any empty space.
+ */
+ rtems_rfs_block_set_bpos_zero (&bpos);
+
+ while (true)
+ {
+ rtems_rfs_block_no block;
+ uint8_t* entry;
+ int offset;
+ bool read = true;
+
+ /*
+ * Locate the first block. If an error the block will be 0. If the map is
+ * empty which happens when creating a directory and adding the first entry
+ * the seek will return ENXIO. In this case we need to grow the directory.
+ */
+ rc = rtems_rfs_block_map_find (fs, &map, &bpos, &block);
+ if (rc > 0)
+ {
+ if (rc != ENXIO)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
+ printf ("rtems-rfs: dir-add-entry: " \
+ "block map find failed for ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (dir), rc, strerror (rc));
+ break;
+ }
+
+ /*
+ * We have reached the end of the directory so add a block.
+ */
+ rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
+ printf ("rtems-rfs: dir-add-entry: " \
+ "block map grow failed for ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (dir), rc, strerror (rc));
+ break;
+ }
+
+ read = false;
+ }
+
+ bpos.bno++;
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, read);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
+ printf ("rtems-rfs: dir-add-entry: " \
+ "block buffer req failed for ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (dir), rc, strerror (rc));
+ break;
+ }
+
+ entry = rtems_rfs_buffer_data (&buffer);
+
+ if (!read)
+ memset (entry, 0xff, rtems_rfs_fs_block_size (fs));
+
+ offset = 0;
+
+ while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
+ {
+ rtems_rfs_ino eino;
+ int elength;
+
+ elength = rtems_rfs_dir_entry_length (entry);
+ eino = rtems_rfs_dir_entry_ino (entry);
+
+ if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
+ {
+ if ((length + RTEMS_RFS_DIR_ENTRY_SIZE) <
+ (rtems_rfs_fs_block_size (fs) - offset))
+ {
+ uint32_t hash;
+ hash = rtems_rfs_dir_hash (name, length);
+ rtems_rfs_dir_set_entry_hash (entry, hash);
+ rtems_rfs_dir_set_entry_ino (entry, ino);
+ rtems_rfs_dir_set_entry_length (entry,
+ RTEMS_RFS_DIR_ENTRY_SIZE + length);
+ memcpy (entry + RTEMS_RFS_DIR_ENTRY_SIZE, name, length);
+ rtems_rfs_buffer_mark_dirty (&buffer);
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return 0;
+ }
+
+ break;
+ }
+
+ if ((elength <= RTEMS_RFS_DIR_ENTRY_SIZE)
+ || (elength >= rtems_rfs_fs_max_name (fs))
+ || (eino < RTEMS_RFS_ROOT_INO)
+ || (eino >= rtems_rfs_fs_inodes (fs)))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_ADD_ENTRY))
+ printf ("rtems-rfs: dir-add-entry: " \
+ "bad length or ino for ino %lu: %u/%ld @ %04x\n",
+ rtems_rfs_inode_ino (dir), elength, eino, offset);
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return EIO;
+ }
+
+ entry += elength;
+ offset += elength;
+ }
+ }
+
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+}
+
+int
+rtems_rfs_dir_del_entry (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir,
+ rtems_rfs_ino ino,
+ uint32_t offset)
+{
+ rtems_rfs_block_map map;
+ rtems_rfs_block_no block;
+ rtems_rfs_buffer_handle buffer;
+ bool search;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
+ printf ("rtems-rfs: dir-del-entry: dir=%ld, entry=%ld offset=%lu\n",
+ rtems_rfs_inode_ino (dir), ino, offset);
+
+ rc = rtems_rfs_block_map_open (fs, dir, &map);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
+ if (rc > 0)
+ {
+ if (rc == ENXIO)
+ rc = ENOENT;
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ /*
+ * Only search if the offset is 0 else we are at that position.
+ */
+ search = offset ? false : true;
+
+ while (rc == 0)
+ {
+ uint8_t* entry;
+ int offset;
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
+ printf ("rtems-rfs: dir-del-entry: " \
+ "block buffer req failed for ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (dir), rc, strerror (rc));
+ break;
+ }
+
+ entry = rtems_rfs_buffer_data (&buffer);
+ offset = 0;
+
+ while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
+ {
+ rtems_rfs_ino eino;
+ int elength;
+
+ elength = rtems_rfs_dir_entry_length (entry);
+ eino = rtems_rfs_dir_entry_ino (entry);
+
+ if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
+ break;
+
+ if ((elength <= RTEMS_RFS_DIR_ENTRY_SIZE)
+ || (elength >= rtems_rfs_fs_max_name (fs))
+ || (eino < RTEMS_RFS_ROOT_INO)
+ || (eino >= rtems_rfs_fs_inodes (fs)))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
+ printf ("rtems-rfs: dir-del-entry: " \
+ "bad length or ino for ino %lu: %u/%ld @ %04x\n",
+ rtems_rfs_inode_ino (dir), elength, eino, offset);
+ rc = EIO;
+ break;
+ }
+
+ if (ino == rtems_rfs_dir_entry_ino (entry))
+ {
+ uint32_t remaining;
+ remaining = rtems_rfs_fs_block_size (fs) - (offset + elength);
+ memmove (entry, entry + elength, remaining);
+ memset (entry + remaining, 0xff, elength);
+
+ /*
+ * If the remainder of the block is empty and this is the start of the
+ * block and it is the last block in the map shrink the map.
+ *
+ * @note We could check again to see if the new end block in the map is
+ * also empty. This way we could clean up an empty directory.
+ */
+ elength = rtems_rfs_dir_entry_length (entry);
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
+ printf ("rtems-rfs: dir-del-entry: " \
+ "last block free for ino %lu: elength=%i offset=%d last=%s\n",
+ ino, elength, offset,
+ rtems_rfs_block_map_last (&map) ? "yes" : "no");
+
+ if ((elength == RTEMS_RFS_DIR_ENTRY_EMPTY) &&
+ (offset == 0) && rtems_rfs_block_map_last (&map))
+ {
+ rc = rtems_rfs_block_map_shrink (fs, &map, 1);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_DEL_ENTRY))
+ printf ("rtems-rfs: dir-del-entry: " \
+ "block map shrink failed for ino %lu: %d: %s\n",
+ rtems_rfs_inode_ino (dir), rc, strerror (rc));
+ }
+ }
+
+ rtems_rfs_buffer_mark_dirty (&buffer);
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return 0;
+ }
+
+ if (!search)
+ {
+ rc = EIO;
+ break;
+ }
+
+ entry += elength;
+ offset += elength;
+ }
+
+ if (rc == 0)
+ {
+ rc = rtems_rfs_block_map_next_block (fs, &map, &block);
+ if (rc == ENXIO)
+ rc = ENOENT;
+ }
+ }
+
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+}
+
+int
+rtems_rfs_dir_read (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir,
+ rtems_rfs_pos_rel offset,
+ struct dirent* dirent,
+ size_t* length)
+{
+ rtems_rfs_block_map map;
+ rtems_rfs_buffer_handle buffer;
+ rtems_rfs_block_no block;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
+ printf ("rtems-rfs: dir-read: dir=%ld offset=%Ld\n",
+ rtems_rfs_inode_ino (dir), offset);
+
+ *length = 0;
+
+ rc = rtems_rfs_block_map_open (fs, dir, &map);
+ if (rc > 0)
+ return rc;
+
+ if (((rtems_rfs_fs_block_size (fs) -
+ (offset % rtems_rfs_fs_block_size (fs))) <= RTEMS_RFS_DIR_ENTRY_SIZE))
+ offset = (((offset / rtems_rfs_fs_block_size (fs)) + 1) *
+ rtems_rfs_fs_block_size (fs));
+
+ rc = rtems_rfs_block_map_seek (fs, &map, offset, &block);
+ if (rc > 0)
+ {
+ if (rc == ENXIO)
+ rc = ENOENT;
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ /*
+ * Look for an empty entry and if this is the last block that is the end of
+ * the directory.
+ */
+ while (rc == 0)
+ {
+ uint8_t* entry;
+ rtems_rfs_ino eino;
+ int elength;
+ int remaining;
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ entry = rtems_rfs_buffer_data (&buffer);
+ entry += map.bpos.boff;
+
+ elength = rtems_rfs_dir_entry_length (entry);
+ eino = rtems_rfs_dir_entry_ino (entry);
+
+ if (elength != RTEMS_RFS_DIR_ENTRY_EMPTY)
+ {
+ if ((elength <= RTEMS_RFS_DIR_ENTRY_SIZE)
+ || (elength >= rtems_rfs_fs_max_name (fs))
+ || (eino < RTEMS_RFS_ROOT_INO)
+ || (eino >= rtems_rfs_fs_inodes (fs)))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
+ printf ("rtems-rfs: dir-read: " \
+ "bad length or ino for ino %lu: %u/%ld @ %04lx\n",
+ rtems_rfs_inode_ino (dir), elength, eino, map.bpos.boff);
+ rc = EIO;
+ break;
+ }
+
+ memset (dirent, 0, sizeof (struct dirent));
+ dirent->d_off = offset;
+ dirent->d_reclen = sizeof (struct dirent);
+
+ *length += elength;
+
+ remaining = rtems_rfs_fs_block_size (fs) - (map.bpos.boff + elength);
+
+ if (remaining <= RTEMS_RFS_DIR_ENTRY_SIZE)
+ *length += remaining;
+
+ if (elength < RTEMS_RFS_DIR_ENTRY_SIZE)
+ elength = 0;
+ else
+ elength -= RTEMS_RFS_DIR_ENTRY_SIZE;
+ if (elength > NAME_MAX)
+ elength = NAME_MAX;
+
+ memcpy (dirent->d_name, entry + RTEMS_RFS_DIR_ENTRY_SIZE, elength);
+
+ dirent->d_ino = rtems_rfs_dir_entry_ino (entry);
+ dirent->d_namlen = elength;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
+ printf ("rtems-rfs: dir-read: found off:%ld ino:%ld name=%s\n",
+ dirent->d_off, dirent->d_ino, dirent->d_name);
+ break;
+ }
+
+ *length += rtems_rfs_fs_block_size (fs) - map.bpos.boff;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
+ printf ("rtems-rfs: dir-read: next block: off:%ld length:%ld\n",
+ (uint32_t) offset, *length);
+
+ rc = rtems_rfs_block_map_next_block (fs, &map, &block);
+ if (rc == ENXIO)
+ rc = ENOENT;
+ }
+
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+}
+
+int
+rtems_rfs_dir_empty (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir)
+{
+ rtems_rfs_block_map map;
+ rtems_rfs_buffer_handle buffer;
+ rtems_rfs_block_no block;
+ bool empty;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_READ))
+ printf ("rtems-rfs: dir-empty: dir=%ld\n", rtems_rfs_inode_ino (dir));
+
+ empty = true;
+
+ rc = rtems_rfs_block_map_open (fs, dir, &map);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+ }
+
+ /*
+ * Look for an empty entry and if this is the last block that is the end of
+ * the directory.
+ */
+ while (empty)
+ {
+ uint8_t* entry;
+ int offset;
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
+ if (rc > 0)
+ break;
+
+ entry = rtems_rfs_buffer_data (&buffer);
+ offset = 0;
+
+ while (offset < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE))
+ {
+ rtems_rfs_ino eino;
+ int elength;
+
+ elength = rtems_rfs_dir_entry_length (entry);
+ eino = rtems_rfs_dir_entry_ino (entry);
+
+ if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
+ break;
+
+ if ((elength <= RTEMS_RFS_DIR_ENTRY_SIZE)
+ || (elength >= rtems_rfs_fs_max_name (fs))
+ || (eino < RTEMS_RFS_ROOT_INO)
+ || (eino >= rtems_rfs_fs_inodes (fs)))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_DIR_EMPTY))
+ printf ("rtems-rfs: dir-empty: " \
+ "bad length or ino for ino %lu: %u/%ld @ %04x\n",
+ rtems_rfs_inode_ino (dir), elength, eino, offset);
+ rc = EIO;
+ break;
+ }
+
+ /*
+ * Ignore the current (.) and parent (..) entries. Anything else means
+ * the directory is not empty.
+ */
+ if (((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 1)) ||
+ (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.')) &&
+ ((elength != (RTEMS_RFS_DIR_ENTRY_SIZE + 2)) ||
+ (entry[RTEMS_RFS_DIR_ENTRY_SIZE] != '.') ||
+ (entry[RTEMS_RFS_DIR_ENTRY_SIZE + 1] != '.')))
+ {
+ empty = false;
+ break;
+ }
+
+ entry += elength;
+ offset += elength;
+ }
+
+ if (empty)
+ {
+ rc = rtems_rfs_block_map_next_block (fs, &map, &block);
+ if (rc > 0)
+ {
+ if (rc == ENXIO)
+ rc = 0;
+ break;
+ }
+ }
+ }
+
+ if ((rc == 0) && !empty)
+ rc = ENOTEMPTY;
+
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_block_map_close (fs, &map);
+ return rc;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-dir.h b/cpukit/libfs/src/rfs/rtems-rfs-dir.h
new file mode 100644
index 0000000000..2852908ea7
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-dir.h
@@ -0,0 +1,206 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Directory Support
+ *
+ * This file provides the directory support functions.
+ */
+
+#if !defined (_RTEMS_RFS_DIR_H_)
+#define _RTEMS_RFS_DIR_H_
+
+#include <dirent.h>
+
+#include <rtems/libio_.h>
+
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+
+/**
+ * Test if the path provided is a current directory.
+ *
+ * @param _p Pointer to the path string.
+ * @return bool True if the path is a current directory.
+ */
+#define rtems_rfs_current_dir(_p) \
+ ((_p[0] == '.') && ((_p[1] == '\0') || rtems_filesystem_is_separator (_p[1])))
+
+/**
+ * Test if the path provided is a parent directory.
+ *
+ * @param _p Pointer to the path string.
+ * @return bool True if the path is a parent directory.
+ */
+#define rtems_rfs_parent_dir(_p) \
+ ((_p[0] == '.') && (_p[1] == '.') && \
+ ((_p[2] == '\0') || rtems_filesystem_is_separator (_p[2])))
+
+/**
+ * Define the offsets of the fields of a directory entry.
+ */
+#define RTEMS_RFS_DIR_ENTRY_INO (0) /**< The ino offset in a directory
+ * entry. */
+#define RTEMS_RFS_DIR_ENTRY_HASH (4) /**< The hash offset in a directory
+ * entry. The hash is 32bits. We need at
+ * least 16bits and given the length and
+ * ino field are 4 the extra 2 bytes is
+ * not a big overhead.*/
+#define RTEMS_RFS_DIR_ENTRY_LEN (8) /**< The length offset in a directory
+ * entry. */
+
+/**
+ * The length of the directory entry header.
+ */
+#define RTEMS_RFS_DIR_ENTRY_SIZE (4 + 4 + 2)
+
+/**
+ * The length when the remainder of the directory block is empty.
+ */
+#define RTEMS_RFS_DIR_ENTRY_EMPTY (0xffff)
+
+/**
+ * Return the hash of the entry.
+ *
+ * @param _e Pointer to the directory entry.
+ * @return uint32_t The hash.
+ */
+#define rtems_rfs_dir_entry_hash(_e) \
+ rtems_rfs_read_u32 (_e + RTEMS_RFS_DIR_ENTRY_HASH)
+
+/**
+ * Set the hash of the entry.
+ *
+ * @param _e Pointer to the directory entry.
+ * @aparam _h The hash.
+ */
+#define rtems_rfs_dir_set_entry_hash(_e, _h) \
+ rtems_rfs_write_u32 (_e + RTEMS_RFS_DIR_ENTRY_HASH, _h)
+
+/**
+ * Return the ino of the entry.
+ *
+ * @param _e Pointer to the directory entry.
+ * @return uint32_t The ino.
+ */
+#define rtems_rfs_dir_entry_ino(_e) \
+ rtems_rfs_read_u32 (_e + RTEMS_RFS_DIR_ENTRY_INO)
+
+/**
+ * Set the ino of the entry.
+ *
+ * @param _e Pointer to the directory entry.
+ * @param _i The ino.
+ */
+#define rtems_rfs_dir_set_entry_ino(_e, _i) \
+ rtems_rfs_write_u32 (_e + RTEMS_RFS_DIR_ENTRY_INO, _i)
+
+/**
+ * Return the length of the entry.
+ *
+ * @param _e Pointer to the directory entry.
+ * @return uint16_t The length.
+ */
+#define rtems_rfs_dir_entry_length(_e) \
+ rtems_rfs_read_u16 (_e + RTEMS_RFS_DIR_ENTRY_LEN)
+
+/**
+ * Set the length of the entry.
+ *
+ * @param _e Pointer to the directory entry.
+ * @param _l The length.
+ */
+#define rtems_rfs_dir_set_entry_length(_e, _l) \
+ rtems_rfs_write_u16 (_e + RTEMS_RFS_DIR_ENTRY_LEN, _l)
+
+/**
+ * Look up a directory entry in the directory pointed to by the inode. The look
+ * up is local to this directory. No need to decend.
+ *
+ * @param fs The file system.
+ * @param inode The inode of the directory to search.
+ * @param name The name to look up. The name may not be nul terminated.
+ * @param length The length of the name.
+ * @param ino The return inode number if there is no error.
+ * @param offset The offset in the directory for the entry.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_dir_lookup_ino (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* inode,
+ const char* path,
+ int length,
+ rtems_rfs_ino* ino,
+ uint32_t* offset);
+
+/**
+ * Add an entry to the directory returing the inode number allocated to the
+ * entry.
+ *
+ * @param fs The file system data.
+ * @param dir Pointer to the directory inode the entry is to be added too.
+ * @param name The name of the entry to be added.
+ * @param length The length of the name excluding a terminating \0.
+ * @param ino The ino of the entry.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_dir_add_entry (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir,
+ const char* name,
+ size_t length,
+ rtems_rfs_ino ino);
+
+/**
+ * Del an entry from the directory using an inode number as a key.
+ *
+ * @param fs The file system data.
+ * @param dir Pointer to the directory inode the entry is to be deleted from.
+ * @param ino The ino of the entry.
+ * @param offset The offset in the directory of the entry to delete. If 0
+ * search from the start for the ino.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_dir_del_entry (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir,
+ rtems_rfs_ino ino,
+ uint32_t offset);
+
+/**
+ * Read the directory entry from offset into the directory entry buffer and
+ * return the length of space this entry uses in the directory table.
+ *
+ * @param fs The file system data.
+ * @param dir The direct inode handler.
+ * @param offset The offset in the directory to read from.
+ * @param dirent Pointer to the dirent structure the entry is written into.
+ * @param length Set the length this entry takes in the directory.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_dir_read (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir,
+ rtems_rfs_pos_rel offset,
+ struct dirent* dirent,
+ size_t* length);
+
+/**
+ * Check if the directory is empty. The current and parent directory entries
+ * are ignored.
+ *
+ * @param fs The file system data
+ * @param dir The directory inode to check.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_dir_empty (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* dir);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-file-system-fwd.h b/cpukit/libfs/src/rfs/rtems-rfs-file-system-fwd.h
new file mode 100644
index 0000000000..7309c60cfd
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-file-system-fwd.h
@@ -0,0 +1,27 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Data forward decl.
+ */
+
+#if !defined (_RTEMS_RFS_FILE_SYSTEM_FWD_H_)
+#define _RTEMS_RFS_FILE_SYSTEM_FWD_H_
+
+/**
+ * Forward reference to the file system data.
+ */
+struct rtems_rfs_file_system_t;
+typedef struct rtems_rfs_file_system_t rtems_rfs_file_system;
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-file-system.c b/cpukit/libfs/src/rfs/rtems-rfs-file-system.c
new file mode 100644
index 0000000000..ce355be824
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-file-system.c
@@ -0,0 +1,278 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Open
+ *
+ * Open the file system by reading the superblock and then the group data.
+ */
+
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+static int
+rtems_rfs_fs_read_superblock (rtems_rfs_file_system* fs)
+{
+ rtems_rfs_buffer_handle handle;
+ uint8_t* sb;
+ int group;
+ int rc;
+
+ rc = rtems_rfs_buffer_handle_open (fs, &handle);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: handle open failed: %d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, true);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: request failed%d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ sb = rtems_rfs_buffer_data (&handle);
+
+#define read_sb(_o) rtems_rfs_read_u32 (sb + (_o))
+
+ if (read_sb (RTEMS_RFS_SB_OFFSET_MAGIC) != RTEMS_RFS_SB_MAGIC)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: invalid superblock, bad magic\n");
+ return EIO;
+ }
+
+ fs->blocks = read_sb (RTEMS_RFS_SB_OFFSET_BLOCKS);
+ fs->block_size = read_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE);
+
+ if (rtems_rfs_fs_size(fs) > rtems_rfs_fs_media_size (fs))
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: invalid superblock block/size count\n");
+ return EIO;
+ }
+
+ fs->bad_blocks = read_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS);
+ fs->max_name_length = read_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH);
+ fs->group_count = read_sb (RTEMS_RFS_SB_OFFSET_GROUPS);
+ fs->group_blocks = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS);
+ fs->group_inodes = read_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES);
+
+ fs->blocks_per_block = rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode_block);
+
+ fs->block_map_singly_blocks =
+ fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS;
+ fs->block_map_doubly_blocks =
+ fs->blocks_per_block * fs->blocks_per_block * RTEMS_RFS_INODE_BLOCKS;
+
+ fs->inodes = fs->group_count * fs->group_inodes;
+
+ fs->inodes_per_block = fs->block_size / sizeof (rtems_rfs_inode);
+
+ if (fs->group_blocks >
+ rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs)))
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: groups blocks larger than block bits\n");
+ return EIO;
+ }
+
+ rtems_rfs_buffer_handle_close (fs, &handle);
+
+ /*
+ * Change the block size to the value in the superblock.
+ */
+ rc = rtems_rfs_buffer_setblksize (fs, rtems_rfs_fs_block_size (fs));
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: invalid superblock block size%d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ fs->groups = calloc (fs->group_count, sizeof (rtems_rfs_group));
+
+ if (!fs->groups)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: no memory for group table\n");
+ return ENOMEM;
+ }
+
+ /*
+ * Perform each phase of group initialisation at the same time. This way we
+ * know how far the initialisation has gone if an error occurs and we need to
+ * close everything.
+ */
+ for (group = 0; group < fs->group_count; group++)
+ {
+ rc = rtems_rfs_group_open (fs,
+ rtems_rfs_fs_block (fs, group, 0),
+ fs->group_blocks,
+ fs->group_inodes,
+ &fs->groups[group]);
+ if (rc > 0)
+ {
+ int g;
+ for (g = 0; g < group; g++)
+ rtems_rfs_group_close (fs, &fs->groups[g]);
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: read-superblock: no memory for group table%d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+int
+rtems_rfs_fs_open (const char* name,
+ void* user,
+ uint32_t flags,
+ rtems_rfs_file_system** fs)
+{
+ rtems_rfs_group* group;
+ size_t group_base;
+ rtems_rfs_inode_handle inode;
+ uint16_t mode;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: %s\n", name);
+
+ *fs = malloc (sizeof (rtems_rfs_file_system));
+ if (!*fs)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: no memory for file system data\n");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ memset (*fs, 0, sizeof (rtems_rfs_file_system));
+
+ (*fs)->user = user;
+ rtems_chain_initialize_empty (&(*fs)->buffers);
+ rtems_chain_initialize_empty (&(*fs)->release);
+ rtems_chain_initialize_empty (&(*fs)->release_modified);
+ rtems_chain_initialize_empty (&(*fs)->file_shares);
+
+ (*fs)->max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS;
+ (*fs)->buffers_count = 0;
+ (*fs)->release_count = 0;
+ (*fs)->release_modified_count = 0;
+ (*fs)->flags = flags;
+
+ group = &(*fs)->groups[0];
+ group_base = 0;
+
+ /*
+ * Open the buffer interface.
+ */
+ rc = rtems_rfs_buffer_open (name, *fs);
+ if (rc > 0)
+ {
+ free (*fs);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: buffer open failed: %d: %s\n",
+ rc, strerror (rc));
+ errno = rc;
+ return -1;
+ }
+
+ rc = rtems_rfs_fs_read_superblock (*fs);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_close (*fs);
+ free (*fs);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: reading superblock: %d: %s\n",
+ rc, strerror (rc));
+ errno = rc;
+ return -1;
+ }
+
+ rc = rtems_rfs_inode_open (*fs, RTEMS_RFS_ROOT_INO, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_close (*fs);
+ free (*fs);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: reading root inode: %d: %s\n",
+ rc, strerror (rc));
+ errno = rc;
+ return -1;
+ }
+
+ if (((*fs)->flags & RTEMS_RFS_FS_FORCE_OPEN) == 0)
+ {
+ mode = rtems_rfs_inode_get_mode (&inode);
+
+ if ((mode == 0xffff) || !RTEMS_RFS_S_ISDIR (mode))
+ {
+ rtems_rfs_inode_close (*fs, &inode);
+ rtems_rfs_buffer_close (*fs);
+ free (*fs);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: invalid root inode mode\n");
+ errno = EIO;
+ return -1;
+ }
+ }
+
+ rc = rtems_rfs_inode_close (*fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_close (*fs);
+ free (*fs);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_OPEN))
+ printf ("rtems-rfs: open: closing root inode: %d: %s\n", rc, strerror (rc));
+ errno = rc;
+ return -1;
+ }
+
+ errno = 0;
+ return 0;
+}
+
+int
+rtems_rfs_fs_close (rtems_rfs_file_system* fs)
+{
+ int group;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_CLOSE))
+ printf ("rtems-rfs: close\n");
+
+ for (group = 0; group < fs->group_count; group++)
+ rtems_rfs_group_close (fs, &fs->groups[group]);
+
+ rtems_rfs_buffer_close (fs);
+
+ free (fs);
+ return 0;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-file-system.h b/cpukit/libfs/src/rfs/rtems-rfs-file-system.h
new file mode 100644
index 0000000000..7f307a2cd5
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-file-system.h
@@ -0,0 +1,383 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Data
+ *
+ * This file defines the file system data.
+ */
+
+#if !defined (_RTEMS_RFS_FILE_SYSTEM_H_)
+#define _RTEMS_RFS_FILE_SYSTEM_H_
+
+#include <rtems/rfs/rtems-rfs-group.h>
+
+/**
+ * Superblock offsets and values.
+ */
+#define RTEMS_RFS_SB_OFFSET_MAGIC (0)
+#define RTEMS_RFS_SB_MAGIC (0x28092001)
+#define RTEMS_RFS_SB_OFFSET_BLOCK_SIZE (4)
+#define RTEMS_RFS_SB_OFFSET_BLOCKS (8)
+#define RTEMS_RFS_SB_OFFSET_BAD_BLOCKS (12)
+#define RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH (16)
+#define RTEMS_RFS_SB_OFFSET_GROUPS (20)
+#define RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS (24)
+#define RTEMS_RFS_SB_OFFSET_GROUP_INODES (28)
+
+/**
+ * The root inode number. Do not use 0 as this has special meaning in some Unix
+ * operating systems.
+ */
+#define RTEMS_RFS_ROOT_INO (1)
+
+/**
+ * Empty inode number.
+ */
+#define RTEMS_RFS_EMPTY_INO (0)
+
+/**
+ * The number of blocks in the inode. This number effects the size of the inode
+ * and that effects the overhead of the inode tables in a group.
+ */
+#define RTEMS_RFS_INODE_BLOCKS (5)
+
+/**
+ * The inode overhead is the percentage of space reserved for inodes. It is
+ * calculated as the percentage number of blocks in a group. The number of
+ * blocks in a group is the number of bits a block can hold.
+ */
+#define RTEMS_RFS_INODE_OVERHEAD_PERCENTAGE (1)
+
+/**
+ * Number of blocks in the superblock. Yes I know it is a superblock and not
+ * superblocks but if for any reason this needs to change it is handled.
+ */
+#define RTEMS_RFS_SUPERBLOCK_SIZE (1)
+
+/**
+ * The maximum number of buffers held by the file system at any one time.
+ */
+#define RTEMS_RFS_FS_MAX_HELD_BUFFERS (5)
+
+/**
+ * Absolute position. Make a 64bit value.
+ */
+typedef uint64_t rtems_rfs_pos;
+
+/**
+ * Relative position. Make a 64bit value.
+ */
+typedef int64_t rtems_rfs_pos_rel;
+
+/**
+ * Flags to control the file system.
+ */
+#define RTEMS_RFS_FS_BITMAPS_HOLD (1 << 0) /**< Do not release bitmaps
+ * when finished. Default is
+ * off so they are released. */
+#define RTEMS_RFS_FS_NO_LOCAL_CACHE (1 << 1) /**< Do not cache the buffers
+ * and release directly to the
+ * buffer support layer. The
+ * default is to hold buffers. */
+#define RTEMS_RFS_FS_FORCE_OPEN (1 << 2) /**< Force open and ignore any
+ * errors. */
+#define RTEMS_RFS_FS_READ_ONLY (1 << 3) /**< Make the mount
+ * read-only. Currently not
+ * supported. */
+/**
+ * RFS File System data.
+ */
+struct rtems_rfs_file_system_t
+{
+ /**
+ * Flags to control the file system. Some can be controlled via the ioctl.
+ */
+ uint32_t flags;
+
+ /**
+ * The number of blocks in the disk. The size of the disk is the number of
+ * blocks by the block size. This should be within a block size of the size
+ * returned by the media driver.
+ */
+ size_t blocks;
+
+ /**
+ * The size of a block. This must be a multiple of the disk's media block
+ * size.
+ */
+ size_t block_size;
+
+#if RTEMS_RFS_USE_LIBBLOCK
+ /**
+ * The disk device. This is the data about the block device this file system
+ * is mounted on. We access the data held in this structure rather than
+ * making an extra copy in this structure.
+ */
+ rtems_disk_device* disk;
+#else
+ /**
+ * The device number which is a the file handle for device I/O.
+ */
+ dev_t device;
+
+ /**
+ * The number of blocks in the file system.
+ */
+ size_t size;
+#endif
+
+ /**
+ * Inode count.
+ */
+ uint32_t inodes;
+
+ /**
+ * Bad block blocks. This is a table of blocks that have been found to be
+ * bad.
+ */
+ uint32_t bad_blocks;
+
+ /**
+ * Maximum length of names supported by this file system.
+ */
+ uint32_t max_name_length;
+
+ /**
+ * A disk is broken down into a series of groups.
+ */
+ rtems_rfs_group* groups;
+
+ /**
+ * Number of groups.
+ */
+ int group_count;
+
+ /**
+ * Number of blocks in a group.
+ */
+ size_t group_blocks;
+
+ /**
+ * Number of inodes in a group.
+ */
+ size_t group_inodes;
+
+ /**
+ * Number of inodes in each block.
+ */
+ size_t inodes_per_block;
+
+ /**
+ * Number of block numbers in a block.
+ */
+ size_t blocks_per_block;
+
+ /**
+ * Block map single indirect count. This is the block number per block
+ * multiplied but the slots in the inode.
+ */
+ size_t block_map_singly_blocks;
+
+ /**
+ * Block map double indirect count. This is the block number per block
+ * squared and multiplied by the slots in the inode. It is the maximum
+ * number of blocks a map (file/directory) can have.
+ */
+ size_t block_map_doubly_blocks;
+
+ /**
+ * Number of buffers held before releasing back to the cache.
+ */
+ uint32_t max_held_buffers;
+
+ /**
+ * List of buffers attached to buffer handles. Allows sharing.
+ */
+ rtems_chain_control buffers;
+
+ /**
+ * Number of buffers held on the buffers list.
+ */
+ uint32_t buffers_count;
+
+ /**
+ * List of buffers that need to be released when the processing of a file
+ * system request has completed.
+ */
+ rtems_chain_control release;
+
+ /**
+ * Number of buffers held on the release list.
+ */
+ uint32_t release_count;
+
+ /**
+ * List of buffers that need to be released modified when the processing of a
+ * file system request has completed.
+ */
+ rtems_chain_control release_modified;
+
+ /**
+ * Number of buffers held on the release modified list.
+ */
+ uint32_t release_modified_count;
+
+ /**
+ * List of open shared file node data. The shared node data such as the inode
+ * and block map allows a single file to be open more than once.
+ */
+ rtems_chain_control file_shares;
+
+ /**
+ * Pointer to user data supplied when opening.
+ */
+ void* user;
+};
+
+/**
+ * Should bitmap buffers be released when finished ?
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_release_bitmaps(_f) (!((_f)->flags & RTEMS_RFS_FS_BITMAPS_HOLD))
+
+/**
+ * Are the buffers locally cache or released back to the buffering layer ?
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_no_local_cache(_f) ((_f)->flags & RTEMS_RFS_FS_NO_LOCAL_CACHE)
+
+/**
+ * The disk device number.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#if RTEMS_RFS_USE_LIBBLOCK
+#define rtems_rfs_fs_device(_fs) ((_fs)->disk->dev)
+#else
+#define rtems_rfs_fs_device(_fs) ((_fs)->device)
+#endif
+
+/**
+ * The size of the disk in blocks.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_blocks(_fs) ((_fs)->blocks)
+
+/**
+ * The block size.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_block_size(_fs) ((_fs)->block_size)
+
+/**
+ * The size of the disk in bytes.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_size(_fs) (((uint64_t) rtems_rfs_fs_blocks (_fs)) * \
+ rtems_rfs_fs_block_size (_fs))
+
+/**
+ * The number of inodes.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_inodes(_fs) ((_fs)->inodes)
+
+/**
+ * Calculate a block in the file system given the group and the block within
+ * the group.
+ *
+ * @param _fs Pointer to the file system.
+ * @param _grp The group.
+ * @param _blk The block within the group.
+ * @return The absolute block number.
+ */
+#define rtems_rfs_fs_block(_fs, _grp, _blk) \
+ ((((_fs)->group_blocks) * (_grp)) + (_blk) + 1)
+
+/**
+ * The media size of the disk in media size blocks.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#if RTEMS_RFS_USE_LIBBLOCK
+#define rtems_rfs_fs_media_blocks(_fs) ((_fs)->disk->size)
+#else
+#define rtems_rfs_fs_media_blocks(_fs) ((_fs)->media_size)
+#endif
+
+/**
+ * The media block size. This is the size of a block on disk. For a device I/O
+ * this value is 1.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#if RTEMS_RFS_USE_LIBBLOCK
+#define rtems_rfs_fs_media_block_size(_fs) ((_fs)->disk->media_block_size)
+#else
+#define rtems_rfs_fs_media_block_size(_fs) (1)
+#endif
+
+/**
+ * The size of the disk in bytes.
+ *
+ * @param _fs Pointer to the file system.
+ */
+#define rtems_rfs_fs_media_size(_fs) (((uint64_t) rtems_rfs_fs_media_blocks (_fs)) * \
+ rtems_rfs_fs_media_block_size (_fs))
+
+/**
+ * The maximum length of a name supported by the file system.
+ */
+#define rtems_rfs_fs_max_name(_fs) ((_fs)->max_name_length)
+
+/**
+ * Return the maximum number of blocks in a block map.
+ *
+ * @return uint32_t The maximum number of blocks possible.
+ */
+#define rtems_rfs_fs_max_block_map_blocks(_fs) ((_fs)->block_map_doubly_blocks)
+
+/**
+ * Return the user pointer.
+ */
+#define rtems_rfs_fs_user(_fs) ((_fs)->user)
+
+/**
+ * Open the file system given a file path.
+ *
+ * @param name The device to open.
+ * @param fs The file system data filled in by this call.
+ * @param user A pointer to user data.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_fs_open (const char* name,
+ void* user,
+ uint32_t flags,
+ rtems_rfs_file_system** fs);
+
+/**
+ * Close the file system.
+ *
+ * @param fs The file system data.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_fs_close (rtems_rfs_file_system* fs);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-file.c b/cpukit/libfs/src/rfs/rtems-rfs-file.c
new file mode 100644
index 0000000000..33c9196a39
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-file.c
@@ -0,0 +1,573 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems File Routines.
+ *
+ * These functions manage files.
+ */
+
+#include <rtems/rfs/rtems-rfs-block-pos.h>
+#include <rtems/rfs/rtems-rfs-file.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+int
+rtems_rfs_file_open (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino,
+ uint32_t flags,
+ rtems_rfs_file_handle** file)
+{
+ rtems_rfs_file_handle* handle;
+ rtems_rfs_file_shared* shared;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
+ printf ("rtems-rfs: file-open: ino=%ld\n", ino);
+
+ *file = NULL;
+
+ /*
+ * Allocate a new handle and initialise it. Do this before we deal with the
+ * shared node data so we do not have to be concerned with reference
+ * counting.
+ */
+ handle = malloc (sizeof (rtems_rfs_file_handle));
+ if (!handle)
+ return ENOMEM;
+
+ memset (handle, 0, sizeof (rtems_rfs_file_handle));
+
+ rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
+ printf ("rtems-rfs: file-open: buffer handle open failed: %d: %s\n",
+ rc, strerror (rc));
+ free (handle);
+ return rc;
+ }
+
+ /*
+ * Scan the file system data list of open files for this ino. If found up
+ * the reference count and return the pointer to the data.
+ */
+ shared = rtems_rfs_file_get_shared (fs, ino);
+ if (shared)
+ {
+ shared->references++;
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
+ printf ("rtems-rfs: file-open: ino=%ld shared\n", ino);
+ }
+ else
+ {
+ /*
+ * None exists so create. Copy in the shared parts of the inode we hold in
+ * memory.
+ */
+ shared = malloc (sizeof (rtems_rfs_file_shared));
+ if (!shared)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle->buffer);
+ free (handle);
+ return ENOMEM;
+ }
+
+ memset (shared, 0, sizeof (rtems_rfs_file_shared));
+
+ rc = rtems_rfs_inode_open (fs, ino, &shared->inode, true);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
+ printf ("rtems-rfs: file-open: inode open failed: %d: %s\n",
+ rc, strerror (rc));
+ free (shared);
+ rtems_rfs_buffer_handle_close (fs, &handle->buffer);
+ free (handle);
+ return rc;
+ }
+
+ rc = rtems_rfs_block_map_open (fs, &shared->inode, &shared->map);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
+ printf ("rtems-rfs: file-open: block map open failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &shared->inode);
+ free (shared);
+ rtems_rfs_buffer_handle_close (fs, &handle->buffer);
+ free (handle);
+ return rc;
+ }
+
+ shared->references = 1;
+ shared->size.count = rtems_rfs_inode_get_block_count (&shared->inode);
+ shared->size.offset = rtems_rfs_inode_get_block_offset (&shared->inode);
+ shared->atime = rtems_rfs_inode_get_atime (&shared->inode);
+ shared->mtime = rtems_rfs_inode_get_mtime (&shared->inode);
+ shared->ctime = rtems_rfs_inode_get_ctime (&shared->inode);
+ shared->fs = fs;
+
+ rtems_chain_append (&fs->file_shares, &shared->link);
+
+ rtems_rfs_inode_unload (fs, &shared->inode, false);
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_OPEN))
+ printf ("rtems-rfs: file-open: ino=%ld share created\n", ino);
+ }
+
+ handle->flags = flags;
+ handle->shared = shared;
+
+ *file = handle;
+
+ return 0;
+}
+
+int
+rtems_rfs_file_close (rtems_rfs_file_system* fs,
+ rtems_rfs_file_handle* handle)
+{
+ int rrc;
+ int rc;
+
+ rrc = 0;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
+ printf ("rtems-rfs: file-close: entry: ino=%ld\n",
+ handle->shared->inode.ino);
+
+ if (handle->shared->references > 0)
+ handle->shared->references--;
+
+ if (handle->shared->references == 0)
+ {
+ /*
+ * @todo This could be clever and only update if different.
+ */
+ rtems_rfs_inode_set_atime (&handle->shared->inode,
+ handle->shared->atime);
+ rtems_rfs_inode_set_mtime (&handle->shared->inode,
+ handle->shared->mtime);
+ rtems_rfs_inode_set_ctime (&handle->shared->inode,
+ handle->shared->ctime);
+ handle->shared->map.size.count = handle->shared->size.count;
+ handle->shared->map.size.offset = handle->shared->size.offset;
+
+ rc = rtems_rfs_block_map_close (fs, &handle->shared->map);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
+ printf ("rtems-rfs: file-close: map close error: ino=%ld: %d: %s\n",
+ handle->shared->inode.ino, rc, strerror (rc));
+ if (rrc == 0)
+ rrc = rc;
+ }
+
+ rc = rtems_rfs_inode_close (fs, &handle->shared->inode);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
+ printf ("rtems-rfs: file-close: inode close error: ino=%ld: %d: %s\n",
+ handle->shared->inode.ino, rc, strerror (rc));
+ if (rrc == 0)
+ rrc = rc;
+ }
+
+ rtems_chain_extract (&handle->shared->link);
+ free (handle->shared);
+ }
+
+ rc = rtems_rfs_buffer_handle_close (fs, &handle->buffer);
+ if ((rrc == 0) && (rc > 0))
+ rrc = rc;
+
+ if (rrc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_CLOSE))
+ printf ("rtems-rfs: file-close: result: %d: %s\n", rrc, strerror (rrc));
+ }
+
+ free (handle);
+
+ return rrc;
+}
+
+int
+rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
+ size_t* available,
+ bool read)
+{
+ size_t size;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-io: start: %s pos=%lu:%lu\n",
+ read ? "read" : "write", handle->bpos.bno, handle->bpos.boff);
+
+ if (!rtems_rfs_buffer_handle_has_block (&handle->buffer))
+ {
+ rtems_rfs_buffer_block block;
+ bool request_read;
+ int rc;
+
+ request_read = read;
+
+ rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_map (handle),
+ rtems_rfs_file_bpos (handle),
+ &block);
+ if (rc > 0)
+ {
+ /*
+ * Has the read reached the EOF ?
+ */
+ if (read && (rc == ENXIO))
+ {
+ *available = 0;
+ return 0;
+ }
+
+ if (rc != ENXIO)
+ return rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-io: start: grow\n");
+
+ rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_map (handle),
+ 1, &block);
+ if (rc > 0)
+ return rc;
+
+ request_read = false;
+ }
+ else
+ {
+ /*
+ * If this is a write check if the write starts within a block or the
+ * amount of data is less than a block size. If it is read the block
+ * rather than getting a block to fill.
+ */
+ if (!read &&
+ (rtems_rfs_file_block_offset (handle) ||
+ (*available < rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))))
+ request_read = true;
+ }
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-io: start: block=%lu request-read=%s\n",
+ block, request_read ? "yes" : "no");
+
+ rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_buffer (handle),
+ block, request_read);
+ if (rc > 0)
+ return rc;
+ }
+
+ if (read && rtems_rfs_block_map_last (rtems_rfs_file_map (handle)))
+ size = rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
+ else
+ size = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
+
+ *available = size - rtems_rfs_file_block_offset (handle);
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-io: start: available=%lu (%lu)\n",
+ *available, size);
+
+ return 0;
+}
+
+int
+rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
+ size_t size,
+ bool read)
+{
+ bool atime;
+ bool mtime;
+ bool length;
+ int rc = 0;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-io: end: %s size=%lu\n",
+ read ? "read" : "write", size);
+
+ if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
+ {
+ if (!read)
+ rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
+ rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_buffer (handle));
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: file-io: end: error on release: %s size=%lu: %d: %s\n",
+ read ? "read" : "write", size, rc, strerror (rc));
+
+ return rc;
+ }
+ }
+
+ /*
+ * Update the handle's position. Only a block size can be handled at a time
+ * so no special maths is needed. If the offset is bigger than the block size
+ * increase the block number and adjust the offset.
+ *
+ * If we are the last block and the position is past the current size update
+ * the size with the new length. The map holds the block count.
+ */
+ handle->bpos.boff += size;
+
+ if (handle->bpos.boff >=
+ rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle)))
+ {
+ handle->bpos.bno++;
+ handle->bpos.boff -= rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
+ }
+
+ length = false;
+ mtime = false;
+
+ if (!read &&
+ rtems_rfs_block_map_past_end (rtems_rfs_file_map (handle),
+ rtems_rfs_file_bpos (handle)))
+ {
+ rtems_rfs_block_map_set_size_offset (rtems_rfs_file_map (handle),
+ handle->bpos.boff);
+ length = true;
+ mtime = true;
+ }
+
+ atime = rtems_rfs_file_update_atime (handle);
+ mtime = rtems_rfs_file_update_mtime (handle) && mtime;
+ length = rtems_rfs_file_update_length (handle) && length;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-io: end: pos=%lu:%lu %c %c %c\n",
+ handle->bpos.bno, handle->bpos.boff,
+ atime ? 'A' : '-', mtime ? 'M' : '-', length ? 'L' : '-');
+
+ if (atime || mtime)
+ {
+ time_t now = time (NULL);
+ if (read && atime)
+ handle->shared->atime = now;
+ if (!read && mtime)
+ handle->shared->mtime = now;
+ }
+ if (length)
+ {
+ handle->shared->size.count =
+ rtems_rfs_block_map_count (rtems_rfs_file_map (handle));
+ handle->shared->size.offset =
+ rtems_rfs_block_map_size_offset (rtems_rfs_file_map (handle));
+ }
+
+ return rc;
+}
+
+int
+rtems_rfs_file_io_release (rtems_rfs_file_handle* handle)
+{
+ int rc = 0;
+ if (rtems_rfs_buffer_handle_has_block (&handle->buffer))
+ rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_buffer (handle));
+ return rc;
+}
+
+int
+rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
+ rtems_rfs_pos pos,
+ rtems_rfs_pos* new_pos)
+{
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-seek: new=%Lu\n", pos);
+
+ /*
+ * This call only sets the position if it is in a valid part of the file. The
+ * user can request past the end of the file then write to extend the
+ * file. The lseek entry states:
+ *
+ * "Although lseek() may position the file offset beyond the end of the
+ * file, this function does not itself extend the size of the file."
+ *
+ * This means the file needs to set the file size to the pos only when a
+ * write occurs.
+ */
+ if (pos <= rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (handle),
+ handle->shared))
+ rtems_rfs_file_set_bpos (handle, pos);
+
+ *new_pos = pos;
+ return 0;
+}
+
+int
+rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
+ rtems_rfs_pos new_size)
+{
+ rtems_rfs_block_map* map = rtems_rfs_file_map (handle);
+ rtems_rfs_pos size;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_FILE_IO))
+ printf ("rtems-rfs: file-set-size: size=%Lu\n", new_size);
+
+ /*
+ * Short cut for the common truncate on open call.
+ */
+ if (new_size == 0)
+ return rtems_rfs_block_map_free_all (rtems_rfs_file_fs (handle), map);
+
+ size = rtems_rfs_file_size (handle);
+
+ /*
+ * If the file is same size do nothing else grow or shrink it ?
+ */
+ if (size != new_size)
+ {
+ if (size < new_size)
+ {
+ /*
+ * Grow. Fill with 0's.
+ */
+ rtems_rfs_pos count;
+ uint32_t length;
+ bool read_block;
+
+ count = new_size - size;
+ length = rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
+ read_block = false;
+
+ while (count)
+ {
+ rtems_rfs_buffer_block block;
+ rtems_rfs_block_pos bpos;
+ uint8_t* dst;
+ int rc;
+
+ /*
+ * Get the block position for the current end of the file as seen by
+ * the map. If not found and the EOF grow the map then fill the block
+ * with 0.
+ */
+ rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map), &bpos);
+ rc = rtems_rfs_block_map_find (rtems_rfs_file_fs (handle),
+ map, &bpos, &block);
+ if (rc > 0)
+ {
+ /*
+ * Have we reached the EOF ?
+ */
+ if (rc != ENXIO)
+ return rc;
+
+ rc = rtems_rfs_block_map_grow (rtems_rfs_file_fs (handle),
+ map, 1, &block);
+ if (rc > 0)
+ return rc;
+ }
+
+ if (count < (length - bpos.boff))
+ {
+ length = count + bpos.boff;
+ read_block = true;
+ rtems_rfs_block_map_set_size_offset (map, length);
+ }
+ else
+ {
+ rtems_rfs_block_map_set_size_offset (map, 0);
+ }
+
+ /*
+ * Only read the block if the length is not the block size.
+ */
+ rc = rtems_rfs_buffer_handle_request (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_buffer (handle),
+ block, read_block);
+ if (rc > 0)
+ return rc;
+
+ dst = rtems_rfs_buffer_data (&handle->buffer);
+ memset (dst + bpos.boff, 0, length - bpos.boff);
+
+ rtems_rfs_buffer_mark_dirty (rtems_rfs_file_buffer (handle));
+
+ rc = rtems_rfs_buffer_handle_release (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_buffer (handle));
+ if (rc > 0)
+ return rc;
+
+ count -= length - bpos.boff;
+ }
+ }
+ else
+ {
+ /*
+ * Shrink
+ */
+ rtems_rfs_block_no blocks;
+ uint32_t offset;
+
+ blocks =
+ rtems_rfs_block_map_count (map) -
+ (((new_size - 1) /
+ rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle))) + 1);
+
+ offset =
+ new_size % rtems_rfs_fs_block_size (rtems_rfs_file_fs (handle));
+
+ if (blocks)
+ {
+ int rc;
+ rc = rtems_rfs_block_map_shrink (rtems_rfs_file_fs (handle),
+ rtems_rfs_file_map (handle),
+ blocks);
+ if (rc > 0)
+ return rc;
+ }
+
+ rtems_rfs_block_map_set_size_offset (map, offset);
+
+ if (rtems_rfs_block_pos_past_end (rtems_rfs_file_bpos (handle),
+ rtems_rfs_block_map_size (map)))
+ rtems_rfs_block_size_get_bpos (rtems_rfs_block_map_size (map),
+ rtems_rfs_file_bpos (handle));
+ }
+
+ handle->shared->size.count = rtems_rfs_block_map_count (map);
+ handle->shared->size.offset = rtems_rfs_block_map_size_offset (map);
+
+ if (rtems_rfs_file_update_mtime (handle))
+ handle->shared->mtime = time (NULL);
+ }
+
+ return 0;
+}
+
+rtems_rfs_file_shared*
+rtems_rfs_file_get_shared (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino)
+{
+ rtems_chain_node* node;
+ node = rtems_chain_first (&fs->file_shares);
+ while (!rtems_chain_is_tail (&fs->file_shares, node))
+ {
+ rtems_rfs_file_shared* shared;
+ shared = (rtems_rfs_file_shared*) node;
+ if (shared->inode.ino == ino)
+ return shared;
+ node = rtems_chain_next (node);
+ }
+ return NULL;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-file.h b/cpukit/libfs/src/rfs/rtems-rfs-file.h
new file mode 100644
index 0000000000..8467bc951b
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-file.h
@@ -0,0 +1,393 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System File Support
+ *
+ * This file provides the support functions.
+ */
+
+#if !defined (_RTEMS_RFS_FILE_H_)
+#define _RTEMS_RFS_FILE_H_
+
+#include <rtems/libio_.h>
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+
+/**
+ * File data that is shared by various file handles accessing the same file. We
+ * hold various inode values common to the file that can change frequently so
+ * the inode is not thrashed yet we meet the requirements of the POSIX
+ * standard. The stat call needs to check the shared file data.
+ */
+typedef struct rtems_rfs_file_shared_t
+{
+ /**
+ * The shared parts are maintained as a list.
+ */
+ rtems_chain_node link;
+
+ /**
+ * Reference count the users of this data.
+ */
+ int references;
+
+ /**
+ * The inode for the file.
+ */
+ rtems_rfs_inode_handle inode;
+
+ /**
+ * The block map for the file. The handle holds the file's position not the
+ * map.
+ */
+ rtems_rfs_block_map map;
+
+ /**
+ * The size of the file as taken from the inode. The map's size and
+ * this size should be the same.
+ */
+ rtems_rfs_block_size size;
+
+ /**
+ * The access time. The last time the file was read.
+ */
+ rtems_rfs_time atime;
+
+ /**
+ * The modified time. The last time the file was written too.
+ */
+ rtems_rfs_time mtime;
+
+ /**
+ * The change time. The last time the inode was written too.
+ */
+ rtems_rfs_time ctime;
+
+ /**
+ * Hold a pointer to the file system data so users can take the handle and
+ * use it without the needing to hold the file system data pointer.
+ */
+ rtems_rfs_file_system* fs;
+
+} rtems_rfs_file_shared;
+
+/**
+ * Get the atime.
+ *
+ * @param shared The shared file data.
+ * @return rtems_rfs_time The atime.
+ */
+static inline rtems_rfs_time
+rtems_rfs_file_shared_get_atime (rtems_rfs_file_shared* shared)
+{
+ return shared->atime;
+}
+
+/**
+ * Get the mtime.
+ *
+ * @param shared The shared file data.
+ * @return rtems_rfs_time The mtime.
+ */
+static inline rtems_rfs_time
+rtems_rfs_file_shared_get_mtime (rtems_rfs_file_shared* shared)
+{
+ return shared->mtime;
+}
+
+/**
+ * Get the ctime.
+ *
+ * @param shared The shared file data.
+ * @return rtems_rfs_time The ctime.
+ */
+static inline rtems_rfs_time
+rtems_rfs_file_shared_get_ctime (rtems_rfs_file_shared* shared)
+{
+ return shared->ctime;
+}
+
+/**
+ * Get the block count.
+ *
+ * @param shared The shared file data.
+ * @return uint32_t The block count.
+ */
+static inline uint32_t
+rtems_rfs_file_shared_get_block_count (rtems_rfs_file_shared* shared)
+{
+ return shared->size.count;
+}
+
+/**
+ * Get the block offset.
+ *
+ * @param shared The shared file data.
+ * @return uint16_t The block offset.
+ */
+static inline uint16_t
+rtems_rfs_file_shared_get_block_offset (rtems_rfs_file_shared* shared)
+{
+ return shared->size.offset;
+}
+
+/**
+ * Calculate the size of data.
+ *
+ * @param fs The file system data.
+ * @oaram shared The shared file data.
+ * @return rtems_rfs_pos The data size in bytes.
+ */
+static inline rtems_rfs_pos
+rtems_rfs_file_shared_get_size (rtems_rfs_file_system* fs,
+ rtems_rfs_file_shared* shared)
+{
+ return rtems_rfs_block_get_size (fs, &shared->size);
+}
+
+/**
+ * File flags.
+ */
+#define RTEMS_RFS_FILE_NO_ATIME_UPDATE (1 << 0) /**< Do not update the atime
+ * field in the inode if
+ * set. */
+#define RTEMS_RFS_FILE_NO_MTIME_UPDATE (1 << 1) /**< Do not update the mtime
+ * field in the inode if
+ * set. */
+#define RTEMS_RFS_FILE_NO_LENGTH_UPDATE (1 << 2) /**< Do not update the position
+ * field in the inode if
+ * set. */
+
+/**
+ * File data used to managed an open file.
+ */
+typedef struct rtems_rfs_file_handle_t
+{
+ /**
+ * Special flags that can be controlled by the fctrl call.
+ */
+ uint32_t flags;
+
+ /**
+ * The buffer of data at the file's position.
+ */
+ rtems_rfs_buffer_handle buffer;
+
+ /**
+ * The block position of this file handle.
+ */
+ rtems_rfs_block_pos bpos;
+
+ /**
+ * Pointer to the shared file data.
+ */
+ rtems_rfs_file_shared* shared;
+
+} rtems_rfs_file_handle;
+
+/**
+ * Access the data in the buffer.
+ */
+#define rtems_rfs_file_data(_f) \
+ (rtems_rfs_buffer_data (&(_f)->buffer) + (_f)->bpos.boff)
+
+/**
+ * Return the file system data pointer given a file handle.
+ */
+#define rtems_rfs_file_fs(_f) ((_f)->shared->fs)
+
+/**
+ * Return the file's inode handle pointer given a file handle.
+ */
+#define rtems_rfs_file_inode(_f) (&(_f)->shared->inode)
+
+/**
+ * Return the file's block map pointer given a file handle.
+ */
+#define rtems_rfs_file_map(_f) (&(_f)->shared->map)
+
+/**
+ * Return the file's block position pointer given a file handle.
+ */
+#define rtems_rfs_file_bpos(_f) (&(_f)->bpos)
+
+/**
+ * Return the file's block number given a file handle.
+ */
+#define rtems_rfs_file_block(_f) ((_f)->bpos.bno)
+
+/**
+ * Return the file's block offset given a file handle.
+ */
+#define rtems_rfs_file_block_offset(_f) ((_f)->bpos.boff)
+
+/**
+ * Set the file's block position given a file position (absolute).
+ */
+#define rtems_rfs_file_set_bpos(_f, _p) \
+ rtems_rfs_block_get_bpos (rtems_rfs_file_fs (_f), _p, (&(_f)->bpos))
+
+/**
+ * Return the file's buffer handle pointer given a file handle.
+ */
+#define rtems_rfs_file_buffer(_f) (&(_f)->buffer)
+
+/**
+ * Update the access time field of the inode when reading if flagged to do so.
+ */
+#define rtems_rfs_file_update_atime(_f) \
+ (((_f)->flags & RTEMS_RFS_FILE_NO_ATIME_UPDATE) == 0)
+
+/**
+ * Update the modified time field of the inode when writing if flagged to do so.
+ */
+#define rtems_rfs_file_update_mtime(_f) \
+ (((_f)->flags & RTEMS_RFS_FILE_NO_MTIME_UPDATE) == 0)
+
+/**
+ * Update the length field of the inode.
+ */
+#define rtems_rfs_file_update_length(_f) \
+ (((_f)->flags & RTEMS_RFS_FILE_NO_LENGTH_UPDATE) == 0)
+
+/**
+ * Return the shared size varable.
+ */
+#define rtems_rfs_file_get_size(_f) \
+ (&(_f)->shared->size)
+
+/**
+ * Return the size of file.
+ */
+#define rtems_rfs_file_size(_f) \
+ rtems_rfs_file_shared_get_size (rtems_rfs_file_fs (_f), (_f)->shared)
+
+/**
+ * Return the file block count.
+ */
+#define rtems_rfs_file_size_count(_f) \
+ rtems_rfs_file_shared_get_block_count ((_f)->shared)
+
+/**
+ * Return the file block offset.
+ */
+#define rtems_rfs_file_size_offset(_f) \
+ rtems_rfs_file_shared_get_block_offset ((_f)->shared)
+
+/**
+ * Open a file handle.
+ *
+ * @param fs The file system.
+ * @param ino The inode number of the file to be opened.
+ * @param handle Return the handle pointer in this handle.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_open (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino,
+ uint32_t flags,
+ rtems_rfs_file_handle** handle);
+
+/**
+ * Close an open file handle.
+ *
+ * @param fs The file system.
+ * @param handle The open file handle.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_close (rtems_rfs_file_system* fs,
+ rtems_rfs_file_handle* handle);
+
+/**
+ * Start I/O on a block of a file. This call only requests the block from the
+ * media if reading and makes the buffer available to you the via the
+ * rtems_rfs_file_data interface after the call. The available amount data is
+ * taken from the current file position until the end of the block. The file
+ * position is not adujsted until the I/O ends. An I/O request cannot perform
+ * I/O past the end of a block so the call returns the amount of data
+ * available.
+ *
+ * @param handle The file handle.
+ * @param available The amount of data available for I/O.
+ * @param read The I/O operation is a read so the block is read from the media.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_io_start (rtems_rfs_file_handle* handle,
+ size_t* available,
+ bool read);
+
+/**
+ * End the I/O. Any buffers held in the file handle and returned to the
+ * cache. If inode updating is not disable and the I/O is a read the atime
+ * field is updated and if a write I/O the mtime is updated.
+ *
+ * If the file's position is updated by the size amount.
+ *
+ * @param handle The file handle.
+ * @param size The amount of data read or written.
+ * @param read The I/O was a read if true else it was a write.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_io_end (rtems_rfs_file_handle* handle,
+ size_t size,
+ bool read);
+
+/**
+ * Release the I/O resources without any changes. If data has changed in the
+ * buffer and the buffer was not already released as modified the data will be
+ * lost.
+ *
+ * @param handle The file handle.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_io_release (rtems_rfs_file_handle* handle);
+
+/**
+ * The file to the position returning the old position. The position is
+ * abolute.
+ *
+ * @param handle The file handle.
+ * @param pos The position to seek to.
+ * @param new_pos The actual position.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_seek (rtems_rfs_file_handle* handle,
+ rtems_rfs_pos pos,
+ rtems_rfs_pos* new_pos);
+
+/**
+ * Set the size of the file to the new size. This can extend the file to a new
+ * size.
+ *
+ * @param handle The file handle.
+ * @param size The new size of the file.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_file_set_size (rtems_rfs_file_handle* handle,
+ rtems_rfs_pos size);
+
+/**
+ * Return the shared file data for an ino.
+ *
+ * @param fs The file system data.
+ * @param ino The inode number to locate the data for.
+ * @return rtems_rfs_file_shared* The shared data or NULL is not located.
+ */
+rtems_rfs_file_shared* rtems_rfs_file_get_shared (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino);
+
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-format.c b/cpukit/libfs/src/rfs/rtems-rfs-format.c
new file mode 100644
index 0000000000..e15905b2f0
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-format.c
@@ -0,0 +1,627 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Format
+ *
+ * Format the file system ready for use.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+#include <rtems/rtems-rfs-format.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+
+/**
+ * Return the number of gigabytes.
+ */
+#define GIGS(_g) ((_g) * 1024 * 1024)
+
+/**
+ * Return the number of bits that fit in the block size.
+ */
+static int
+rtems_rfs_bits_per_block (rtems_rfs_file_system* fs)
+{
+ return rtems_rfs_bitmap_numof_bits (rtems_rfs_fs_block_size (fs));
+}
+
+/**
+ * Return a rounded up integer quotient given a dividend and divisor. That is:
+ * "quotient = dividend / divisor"
+ */
+int
+rtems_rfs_rup_quotient (uint32_t dividend, uint32_t divisor)
+{
+ if (dividend == 0)
+ return 1;
+ return ((dividend - 1) / divisor) + 1;
+}
+
+/**
+ * Return the number of inodes as a percentage of the total number that can fit
+ * in a blocl.
+ */
+static int
+rtems_rfs_inodes_from_percent (rtems_rfs_file_system* fs,
+ int percentage)
+{
+ int blocks;
+ blocks = (rtems_rfs_bits_per_block (fs) * percentage) / 100;
+ return blocks * (rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode));
+}
+
+/**
+ * Return the inode overhead given a number of inodes.
+ */
+static int
+rtems_rfs_inode_overhead (rtems_rfs_file_system* fs)
+{
+ int blocks;
+ blocks =
+ (fs->group_inodes * sizeof (rtems_rfs_inode)) / rtems_rfs_fs_block_size (fs);
+ return ((blocks + 1) * 100 * 10) / rtems_rfs_bits_per_block (fs);
+}
+
+static bool
+rtems_rfs_check_config (rtems_rfs_file_system* fs,
+ const rtems_rfs_format_config* config)
+{
+ fs->block_size = config->block_size;
+ if (!fs->block_size)
+ {
+ uint64_t total_size = rtems_rfs_fs_media_size (fs);
+
+ if (total_size > GIGS (2))
+ {
+ uint32_t gigs = (total_size + GIGS (1)) / GIGS (1);
+ int b;
+ for (b = 31; b > 0; b--)
+ if ((gigs & (1 << b)) != 0)
+ break;
+ fs->block_size = 1 << b;
+ }
+
+ if (fs->block_size < 1024)
+ fs->block_size = 1024;
+
+ if (fs->block_size > (4 * 1024))
+ fs->block_size = (4 * 1024);
+ }
+
+ if ((fs->block_size % rtems_rfs_fs_media_block_size (fs)) != 0)
+ {
+ printf ("block size (%ld) is not a multiple of media block size (%ld)\n",
+ fs->block_size, rtems_rfs_fs_media_block_size (fs));
+ return false;
+ }
+
+ fs->group_blocks = config->group_blocks;
+ if (!fs->group_blocks)
+ {
+ /*
+ * The number of blocks per group is defined by the number of bits in a
+ * block.
+ */
+ fs->group_blocks = rtems_rfs_bitmap_numof_bits (fs->block_size);
+ }
+
+ if (fs->group_blocks > rtems_rfs_bitmap_numof_bits (fs->block_size))
+ {
+ printf ("group block count is higher than bits in block\n");
+ return false;
+ }
+
+ fs->group_inodes = config->group_inodes;
+ if (!fs->group_inodes)
+ {
+ int inode_overhead = RTEMS_RFS_INODE_OVERHEAD_PERCENTAGE;
+
+ /*
+ * The number of inodes per group is set as a percentage.
+ */
+ if (config->inode_overhead)
+ inode_overhead = config->inode_overhead;
+
+ fs->group_inodes = rtems_rfs_inodes_from_percent (fs, inode_overhead);
+ }
+
+ /*
+ * Round up to fill a block because the minimum allocation unit is a block.
+ */
+ fs->inodes_per_block = rtems_rfs_fs_block_size (fs) / sizeof (rtems_rfs_inode);
+ fs->group_inodes =
+ rtems_rfs_rup_quotient (fs->group_inodes,
+ fs->inodes_per_block) * fs->inodes_per_block;
+
+ if (fs->group_inodes > rtems_rfs_bitmap_numof_bits (fs->block_size))
+ fs->group_inodes = rtems_rfs_bitmap_numof_bits (fs->block_size);
+
+ fs->max_name_length = config->max_name_length;
+ if (!fs->max_name_length)
+ {
+ fs->max_name_length = 512;
+ }
+
+ return true;
+}
+
+static bool
+rtems_rfs_write_group (rtems_rfs_file_system* fs,
+ int group,
+ bool initialise_inodes,
+ bool verbose)
+{
+ rtems_rfs_buffer_handle handle;
+ rtems_rfs_bitmap_control bitmap;
+ rtems_rfs_buffer_block group_base;
+ size_t group_size;
+ int blocks;
+ int b;
+ int rc;
+
+ group_base = rtems_rfs_fs_block (fs, group, 0);
+
+ if (group_base > rtems_rfs_fs_blocks (fs))
+ {
+ printf ("rtems-rfs: write-group: group %d base beyond disk limit\n",
+ group);
+ return false;
+ }
+
+ group_size = fs->group_blocks;
+
+ /*
+ * Be nice to strange sizes of disks. These are embedded systems after all
+ * and nice numbers do not always work out. Let the last block pick up the
+ * remainder of the blocks.
+ */
+ if ((group_base + group_size) > rtems_rfs_fs_blocks (fs))
+ group_size = rtems_rfs_fs_blocks (fs) - group_base;
+
+ if (verbose)
+ printf ("\rrtems-rfs: format: group %3d: base = %ld, size = %ld",
+ group, group_base, group_size);
+
+ /*
+ * Open a handle and request an empty buffer.
+ */
+ rc = rtems_rfs_buffer_handle_open (fs, &handle);
+ if (rc > 0)
+ {
+ printf ("\nrtems-rfs: write-group: handle open failed: %d: %s\n",
+ rc, strerror (rc));
+ return false;
+ }
+
+ if (verbose)
+ printf (", blocks");
+
+ /*
+ * Open the block bitmap using the new buffer.
+ */
+ rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
+ group_base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: open block bitmap failed: %d: %s\n",
+ group, rc, strerror (rc));
+ return false;
+ }
+
+ /*
+ * Force the whole buffer to a known state. The bit map may not occupy the
+ * whole block.
+ */
+ memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
+
+ /*
+ * Clear the bitmap.
+ */
+ rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
+ if (rc > 0)
+ {
+ rtems_rfs_bitmap_close (&bitmap);
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: block bitmap clear all failed: %d: %s\n",
+ group, rc, strerror (rc));
+ return false;
+ }
+
+ /*
+ * Forced allocation of the block bitmap.
+ */
+ rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
+
+ /*
+ * Forced allocation of the inode bitmap.
+ */
+ rtems_rfs_bitmap_map_set (&bitmap, RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
+
+ /*
+ * Determine the number of inodes blocks in the group.
+ */
+ blocks = rtems_rfs_rup_quotient (fs->group_inodes, fs->inodes_per_block);
+
+ /*
+ * Forced allocation of the inode blocks which follow the block bitmap.
+ */
+ for (b = 0; b < blocks; b++)
+ rtems_rfs_bitmap_map_set (&bitmap, b + RTEMS_RFS_GROUP_INODE_BLOCK);
+
+ /*
+ * Close the block bitmap.
+ */
+ rc = rtems_rfs_bitmap_close (&bitmap);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: close block bitmap failed: %d: %s\n",
+ group, rc, strerror (rc));
+ return false;
+ }
+
+ rtems_rfs_buffer_mark_dirty (&handle);
+
+ if (verbose)
+ printf (", inodes");
+
+ /*
+ * Open the inode bitmap using the old buffer. Should release any changes.
+ */
+ rc = rtems_rfs_bitmap_open (&bitmap, fs, &handle, group_size,
+ group_base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: open inode bitmap failed: %d: %s\n",
+ group, rc, strerror (rc));
+ return false;
+ }
+
+ /*
+ * Force the whole buffer to a known state. The bit map may not occupy the
+ * whole block.
+ */
+ memset (rtems_rfs_buffer_data (&handle), 0x00, rtems_rfs_fs_block_size (fs));
+
+ /*
+ * Clear the inode bitmap.
+ */
+ rc = rtems_rfs_bitmap_map_clear_all (&bitmap);
+ if (rc > 0)
+ {
+ rtems_rfs_bitmap_close (&bitmap);
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: inode bitmap" \
+ " clear all failed: %d: %s\n", group, rc, strerror (rc));
+ return false;
+ }
+
+ /*
+ * Close the inode bitmap.
+ */
+ rc = rtems_rfs_bitmap_close (&bitmap);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: close inode" \
+ " bitmap failed: %d: %s\n", group, rc, strerror (rc));
+ return false;
+ }
+
+ rtems_rfs_buffer_mark_dirty (&handle);
+
+ /*
+ * Initialise the inode tables if rerquired to do so.
+ */
+ if (initialise_inodes)
+ {
+ for (b = 0; b < blocks; b++)
+ {
+ rc = rtems_rfs_buffer_handle_request (fs, &handle,
+ group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
+ false);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("\nrtems-rfs: write-group: group %3d: block %ld request failed: %d: %s\n",
+ group, group_base + b + RTEMS_RFS_GROUP_INODE_BLOCK,
+ rc, strerror (rc));
+ return false;
+ }
+
+ /*
+ * Force the whole buffer to a known state. The bit map may not occupy the
+ * whole block.
+ */
+ memset (rtems_rfs_buffer_data (&handle), 0xff, rtems_rfs_fs_block_size (fs));
+
+ rtems_rfs_buffer_mark_dirty (&handle);
+ }
+ }
+
+ rc = rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rc > 0)
+ {
+ printf ("\nrtems-rfs: write-group: buffer handle close failed: %d: %s\n",
+ rc, strerror (rc));
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+rtems_rfs_write_superblock (rtems_rfs_file_system* fs)
+{
+ rtems_rfs_buffer_handle handle;
+ uint8_t* sb;
+ int rc;
+
+ rc = rtems_rfs_buffer_handle_open (fs, &handle);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: write-superblock: handle open failed: %d: %s\n",
+ rc, strerror (rc));
+ return false;
+ }
+
+ rc = rtems_rfs_buffer_handle_request (fs, &handle, 0, false);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("rtems-rfs: write-superblock: request failed: %d: %s\n",
+ rc, strerror (rc));
+ return false;
+ }
+
+ sb = rtems_rfs_buffer_data (&handle);
+
+#define write_sb(_o, _d) rtems_rfs_write_u32(sb + (_o), _d)
+
+ memset (sb, 0xff, rtems_rfs_fs_block_size (fs));
+
+ write_sb (RTEMS_RFS_SB_OFFSET_MAGIC, RTEMS_RFS_SB_MAGIC);
+ write_sb (RTEMS_RFS_SB_OFFSET_BLOCKS, rtems_rfs_fs_blocks (fs));
+ write_sb (RTEMS_RFS_SB_OFFSET_BLOCK_SIZE, rtems_rfs_fs_block_size (fs));
+ write_sb (RTEMS_RFS_SB_OFFSET_BAD_BLOCKS, fs->bad_blocks);
+ write_sb (RTEMS_RFS_SB_OFFSET_MAX_NAME_LENGTH, fs->max_name_length);
+ write_sb (RTEMS_RFS_SB_OFFSET_GROUPS, fs->group_count);
+ write_sb (RTEMS_RFS_SB_OFFSET_GROUP_BLOCKS, fs->group_blocks);
+ write_sb (RTEMS_RFS_SB_OFFSET_GROUP_INODES, fs->group_inodes);
+
+ rtems_rfs_buffer_mark_dirty (&handle);
+
+ rc = rtems_rfs_buffer_handle_release (fs, &handle);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &handle);
+ printf ("rtems-rfs: write-superblock: buffer release failed: %d: %s\n",
+ rc, strerror (rc));
+ return false;
+ }
+
+ rc = rtems_rfs_buffer_handle_close (fs, &handle);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: write-superblock: buffer handle close failed: %d: %s\n",
+ rc, strerror (rc));
+ return false;
+ }
+
+ return true;
+}
+
+static int
+rtems_rfs_write_root_dir (const char* name)
+{
+ rtems_rfs_file_system* fs;
+ rtems_rfs_inode_handle inode;
+ rtems_rfs_ino ino;
+ int rc;
+
+ /*
+ * External API so returns -1.
+ */
+ rc = rtems_rfs_fs_open (name, NULL, RTEMS_RFS_FS_FORCE_OPEN, &fs);
+ if (rc < 0)
+ {
+ printf ("rtems-rfs: format: file system open failed: %d: %s\n",
+ errno, strerror (errno));
+ return -1;
+ }
+
+ rc = rtems_rfs_inode_alloc (fs, RTEMS_RFS_ROOT_INO, &ino);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: format: inode allocation failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_fs_close (fs);
+ return rc;
+ }
+
+ if (ino != RTEMS_RFS_ROOT_INO)
+ {
+ printf ("rtems-rfs: format: allocated inode not root ino: %ld\n", ino);
+ rtems_rfs_fs_close (fs);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: format: inode open failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_group_bitmap_free (fs, true, ino);
+ rtems_rfs_fs_close (fs);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_initialise (&inode, 0,
+ (RTEMS_RFS_S_IFDIR | RTEMS_RFS_S_IRWXU |
+ RTEMS_RFS_S_IXGRP | RTEMS_RFS_S_IXOTH),
+ 0, 0);
+ if (rc > 0)
+ printf ("rtems-rfs: format: inode initialise failed: %d: %s\n",
+ rc, strerror (rc));
+
+ rc = rtems_rfs_dir_add_entry (fs, &inode, ".", 1, ino);
+ if (rc > 0)
+ printf ("rtems-rfs: format: directory add failed: %d: %s\n",
+ rc, strerror (rc));
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ printf ("rtems-rfs: format: inode close failed: %d: %s\n",
+ rc, strerror (rc));
+
+ rc = rtems_rfs_fs_close (fs);
+ if (rc < 0)
+ printf ("rtems-rfs: format: file system close failed: %d: %s\n",
+ errno, strerror (errno));
+
+ return rc;
+}
+
+int
+rtems_rfs_format (const char* name, const rtems_rfs_format_config* config)
+{
+ rtems_rfs_file_system fs;
+ int group;
+ int rc;
+
+ if (config->verbose)
+ printf ("rtems-rfs: format: %s\n", name);
+
+ memset (&fs, 0, sizeof (rtems_rfs_file_system));
+
+ rtems_chain_initialize_empty (&fs.release);
+ rtems_chain_initialize_empty (&fs.release_modified);
+ rtems_chain_initialize_empty (&fs.file_shares);
+
+ fs.max_held_buffers = RTEMS_RFS_FS_MAX_HELD_BUFFERS;
+
+ fs.release_count = 0;
+ fs.release_modified_count = 0;
+
+ fs.flags = RTEMS_RFS_FS_NO_LOCAL_CACHE;
+
+ /*
+ * Open the buffer interface.
+ */
+ rc = rtems_rfs_buffer_open (name, &fs);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: format: buffer open failed: %d: %s\n",
+ rc, strerror (rc));
+ return -1;
+ }
+
+ /*
+ * Check the media.
+ */
+ if (rtems_rfs_fs_media_block_size (&fs) == 0)
+ {
+ printf ("rtems-rfs: media block is invalid: %lu\n",
+ rtems_rfs_fs_media_block_size (&fs));
+ return -1;
+ }
+
+ /*
+ * Check the configuration data.
+ */
+ if (!rtems_rfs_check_config (&fs, config))
+ return -1;
+
+ fs.blocks = rtems_rfs_fs_media_size (&fs) / fs.block_size;
+
+ /*
+ * The bits per block sets the upper limit for the number of blocks in a
+ * group. The disk will be divided into groups which are the number of bits
+ * per block.
+ */
+ fs.group_count =
+ ((rtems_rfs_fs_blocks (&fs) - 1) / rtems_rfs_bits_per_block (&fs)) + 1;
+
+ if (config->verbose)
+ {
+ printf ("rtems-rfs: format: media size = %llu\n",
+ rtems_rfs_fs_media_size (&fs));
+ printf ("rtems-rfs: format: media blocks = %ld\n",
+ rtems_rfs_fs_media_blocks (&fs));
+ printf ("rtems-rfs: format: media block size = %lu\n",
+ rtems_rfs_fs_media_block_size (&fs));
+ printf ("rtems-rfs: format: size = %llu\n",
+ rtems_rfs_fs_size (&fs));
+ printf ("rtems-rfs: format: blocks = %lu\n",
+ rtems_rfs_fs_blocks (&fs));
+ printf ("rtems-rfs: format: block size = %lu\n",
+ rtems_rfs_fs_block_size (&fs));
+ printf ("rtems-rfs: format: bits per block = %u\n",
+ rtems_rfs_bits_per_block (&fs));
+ printf ("rtems-rfs: format: inode size = %lu\n", sizeof (rtems_rfs_inode));
+ printf ("rtems-rfs: format: inodes = %lu (%d.%d%%)\n",
+ fs.group_inodes * fs.group_count,
+ rtems_rfs_inode_overhead (&fs) / 10,
+ rtems_rfs_inode_overhead (&fs) % 10);
+ printf ("rtems-rfs: format: groups = %u\n", fs.group_count);
+ printf ("rtems-rfs: format: group blocks = %lu\n", fs.group_blocks);
+ printf ("rtems-rfs: format: group inodes = %lu\n", fs.group_inodes);
+ }
+
+ rc = rtems_rfs_buffer_setblksize (&fs, rtems_rfs_fs_block_size (&fs));
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: format: setting block size failed: %d: %s\n",
+ rc, strerror (rc));
+ return -1;
+ }
+
+ if (!rtems_rfs_write_superblock (&fs))
+ {
+ printf ("rtems-rfs: format: superblock write failed\n");
+ return -1;
+ }
+
+ for (group = 0; group < fs.group_count; group++)
+ if (!rtems_rfs_write_group (&fs, group,
+ config->initialise_inodes, config->verbose))
+ return -1;
+
+ if (config->verbose)
+ printf ("\n");
+
+ rc = rtems_rfs_buffer_close (&fs);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: format: buffer close failed: %d: %s\n",
+ rc, strerror (rc));
+ return -1;
+ }
+
+ rc = rtems_rfs_write_root_dir (name);
+ if (rc > 0)
+ {
+ printf ("rtems-rfs: format: writing root dir failed: %d: %s\n",
+ rc, strerror (rc));
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-format.h b/cpukit/libfs/src/rfs/rtems-rfs-format.h
new file mode 100644
index 0000000000..41da50781e
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-format.h
@@ -0,0 +1,90 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Format.
+ *
+ * This function lets you format a disk in the RFS format.
+ */
+
+#if !defined (_RTEMS_RFS_FORMAT_H_)
+#define _RTEMS_RFS_FORMAT_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+/**
+ * RFS File System Configuration data used to format the file system. For
+ * default values leave the field set to 0.
+ */
+typedef struct rtems_rfs_format_config_t
+{
+ /**
+ * The size of a block.
+ */
+ size_t block_size;
+
+ /**
+ * The number of blocks in a group.
+ */
+ size_t group_blocks;
+
+ /**
+ * The number of inodes in a group.
+ */
+ size_t group_inodes;
+
+ /**
+ * The percentage overhead allocated to inodes.
+ */
+ int inode_overhead;
+
+ /**
+ * The maximum length of a name.
+ */
+ size_t max_name_length;
+
+ /**
+ * Initialise the inode tables to all ones.
+ */
+ bool initialise_inodes;
+
+ /**
+ * Is the format verbose.
+ */
+ bool verbose;
+
+} rtems_rfs_format_config;
+
+/**
+ * RFS Format command.
+ *
+ * @param name The device name to format.
+ * @param config Pointer to a configuration table.
+ * @retval -1 Error. See errno.
+ * @retval 0 No error. Format successful.
+ */
+int rtems_rfs_format (const char* name, const rtems_rfs_format_config* config);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-group.c b/cpukit/libfs/src/rfs/rtems-rfs-group.c
new file mode 100644
index 0000000000..ef60d320c5
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-group.c
@@ -0,0 +1,316 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Group Routines.
+ *
+ * These functions open and close a group as well as manage bit allocations
+ * within a group.
+ */
+
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-group.h>
+
+int
+rtems_rfs_group_open (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_block base,
+ size_t size,
+ size_t inodes,
+ rtems_rfs_group* group)
+{
+ int rc;
+
+ if (base >= rtems_rfs_fs_blocks (fs))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_OPEN))
+ printf ("rtems-rfs: group-open: base outside file system range: %d: %s\n",
+ EIO, strerror (EIO));
+ return EIO;
+ }
+
+ if ((base + size) >= rtems_rfs_fs_blocks (fs))
+ size = rtems_rfs_fs_blocks (fs) - base;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_OPEN))
+ printf ("rtems-rfs: group-open: base=%ld, blocks=%ld inodes=%ld\n",
+ base, size, inodes);
+
+ group->base = base;
+ group->size = size;
+
+ rc = rtems_rfs_buffer_handle_open (fs, &group->block_bitmap_buffer);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_OPEN))
+ printf ("rtems-rfs: group-open: could not open block bitmap handle: %d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ rc = rtems_rfs_bitmap_open (&group->block_bitmap, fs,
+ &group->block_bitmap_buffer, size,
+ group->base + RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &group->block_bitmap_buffer);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_OPEN))
+ printf ("rtems-rfs: group-open: could not open block bitmap: %d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &group->inode_bitmap_buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_bitmap_close (&group->block_bitmap);
+ rtems_rfs_buffer_handle_close (fs, &group->block_bitmap_buffer);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_OPEN))
+ printf ("rtems-rfs: group-open: could not open inode bitmap handle: %d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ rc = rtems_rfs_bitmap_open (&group->inode_bitmap, fs,
+ &group->inode_bitmap_buffer, inodes,
+ group->base + RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &group->inode_bitmap_buffer);
+ rtems_rfs_bitmap_close (&group->block_bitmap);
+ rtems_rfs_buffer_handle_close (fs, &group->block_bitmap_buffer);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_OPEN))
+ printf ("rtems-rfs: group-open: could not open inode bitmap: %d: %s\n",
+ rc, strerror (rc));
+ return rc;
+ }
+
+ if (rtems_rfs_fs_release_bitmaps (fs))
+ {
+ rtems_rfs_bitmap_release_buffer (fs, &group->block_bitmap);
+ rtems_rfs_bitmap_release_buffer (fs, &group->inode_bitmap);
+ }
+
+ return 0;
+}
+
+int
+rtems_rfs_group_close (rtems_rfs_file_system* fs, rtems_rfs_group* group)
+{
+ int result = 0;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_CLOSE))
+ printf ("rtems-rfs: group-close: base=%ld\n", group->base);
+
+ /*
+ * We need to close as much as possible and also return any error if one
+ * occurs but this may result in one even more important error being lost but
+ * we cannot OR the errors together so this is a reasonable compromise.
+ */
+ rc = rtems_rfs_bitmap_close (&group->inode_bitmap);
+ if (rc > 0)
+ result = rc;
+ rc = rtems_rfs_buffer_handle_close (fs, &group->inode_bitmap_buffer);
+ if (rc > 0)
+ result = rc;
+ rc = rtems_rfs_bitmap_close (&group->block_bitmap);
+ if (rc > 0)
+ result = rc;
+ rc = rtems_rfs_buffer_handle_close (fs, &group->block_bitmap_buffer);
+ if (rc > 0)
+ result = rc;
+
+ return result;
+}
+
+int
+rtems_rfs_group_bitmap_alloc (rtems_rfs_file_system* fs,
+ rtems_rfs_bitmap_bit goal,
+ bool inode,
+ rtems_rfs_bitmap_bit* result)
+{
+ int group_start;
+ size_t size;
+ rtems_rfs_bitmap_bit bit;
+ int offset;
+ bool updown;
+ int direction;
+
+ if (inode)
+ {
+ size = fs->group_inodes;
+ goal -= RTEMS_RFS_ROOT_INO;
+ }
+ else
+ size = fs->group_blocks;
+
+ group_start = goal / size;
+ bit = (rtems_rfs_bitmap_bit) (goal % size);
+ offset = 0;
+ updown = true;
+ direction = 1;
+
+ /*
+ * Try the goal group first and if that group fails try the groups either
+ * side until the whole file system has be tried.
+ */
+ while (true)
+ {
+ rtems_rfs_bitmap_control* bitmap;
+ int group;
+ bool allocated = false;
+ int rc;
+
+ /*
+ * We can start at any location and we move out from that point in each
+ * direction. The offset grows until we find a free bit or we hit an end.
+ */
+ group = group_start + (direction * offset);
+ if (offset)
+ bit = direction > 0 ? 0 : size - 1;
+
+ /*
+ * If we are still looking up and down and if the group is out of range we
+ * have reached one end. Stopping looking up and down and just move in the
+ * one direction one group at a time.
+ */
+ if ((group < 0) || (group >= fs->group_count))
+ {
+ if (!updown)
+ break;
+ direction = direction > 0 ? -1 : 1;
+ updown = false;
+ continue;
+ }
+
+ if (inode)
+ bitmap = &fs->groups[group].inode_bitmap;
+ else
+ bitmap = &fs->groups[group].block_bitmap;
+
+ rc = rtems_rfs_bitmap_map_alloc (bitmap, bit, &allocated, &bit);
+ if (rc > 0)
+ return rc;
+
+ if (rtems_rfs_fs_release_bitmaps (fs))
+ rtems_rfs_bitmap_release_buffer (fs, bitmap);
+
+ if (allocated)
+ {
+ if (inode)
+ *result = rtems_rfs_group_inode (fs, group, bit);
+ else
+ *result = rtems_rfs_group_block (&fs->groups[group], bit);
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_BITMAPS))
+ printf ("rtems-rfs: group-bitmap-alloc: %s allocated: %ld\n",
+ inode ? "inode" : "block", *result);
+ return 0;
+ }
+
+ if (updown)
+ direction = direction > 0 ? -1 : 1;
+
+ offset++;
+ }
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_BITMAPS))
+ printf ("rtems-rfs: group-bitmap-alloc: no blocks available\n");
+
+ return ENOSPC;
+}
+
+int
+rtems_rfs_group_bitmap_free (rtems_rfs_file_system* fs,
+ bool inode,
+ rtems_rfs_bitmap_bit no)
+{
+ rtems_rfs_bitmap_control* bitmap;
+ unsigned int group;
+ rtems_rfs_bitmap_bit bit;
+ size_t size;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_BITMAPS))
+ printf ("rtems-rfs: group-bitmap-free: %s free: %ld\n",
+ inode ? "inode" : "block", no);
+
+ if (inode)
+ {
+ no -= RTEMS_RFS_ROOT_INO;
+ size = fs->group_inodes;
+ }
+ else
+ {
+ no -= RTEMS_RFS_SUPERBLOCK_SIZE;
+ size = fs->group_blocks;
+ }
+
+ group = no / size;
+ bit = (rtems_rfs_bitmap_bit) (no % size);
+
+ if (inode)
+ bitmap = &fs->groups[group].inode_bitmap;
+ else
+ bitmap = &fs->groups[group].block_bitmap;
+
+ rc = rtems_rfs_bitmap_map_clear (bitmap, bit);
+
+ rtems_rfs_bitmap_release_buffer (fs, bitmap);
+
+ return rc;
+}
+
+int
+rtems_rfs_group_bitmap_test (rtems_rfs_file_system* fs,
+ bool inode,
+ rtems_rfs_bitmap_bit no,
+ bool* state)
+{
+ rtems_rfs_bitmap_control* bitmap;
+ unsigned int group;
+ rtems_rfs_bitmap_bit bit;
+ size_t size;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_GROUP_BITMAPS))
+ printf ("rtems-rfs: group-bitmap-test: %s test: %ld\n",
+ inode ? "inode" : "block", no);
+
+ if (inode)
+ {
+ if ((no < RTEMS_RFS_ROOT_INO) || (no > rtems_rfs_fs_inodes (fs)))
+ return EINVAL;
+ no -= RTEMS_RFS_ROOT_INO;
+ size = fs->group_inodes;
+ }
+ else
+ {
+ if (no >= rtems_rfs_fs_blocks (fs))
+ return EINVAL;
+ size = fs->group_blocks;
+ }
+
+ group = no / size;
+ bit = (rtems_rfs_bitmap_bit) (no % size);
+
+ if (inode)
+ bitmap = &fs->groups[group].inode_bitmap;
+ else
+ bitmap = &fs->groups[group].block_bitmap;
+
+ rc = rtems_rfs_bitmap_map_test (bitmap, bit, state);
+
+ rtems_rfs_bitmap_release_buffer (fs, bitmap);
+
+ return rc;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-group.h b/cpukit/libfs/src/rfs/rtems-rfs-group.h
new file mode 100644
index 0000000000..3adf736e2f
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-group.h
@@ -0,0 +1,151 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Group Management.
+ *
+ * These functions manage the groups used in the file system.
+ */
+
+#if !defined (_RTEMS_RFS_GROUP_H_)
+#define _RTEMS_RFS_GROUP_H_
+
+#include <rtems/rfs/rtems-rfs-trace.h>
+#include <rtems/rfs/rtems-rfs-bitmaps.h>
+#include <rtems/rfs/rtems-rfs-buffer.h>
+
+/**
+ * Block allocations for a group on disk.
+ */
+#define RTEMS_RFS_GROUP_BLOCK_BITMAP_BLOCK (0)
+#define RTEMS_RFS_GROUP_INODE_BITMAP_BLOCK (1)
+#define RTEMS_RFS_GROUP_INODE_BLOCK (2)
+
+/**
+ * A group is a selection of blocks on the disk. Typically the number of blocks
+ * in a group is determined by the number of bits a block holds. This makes the
+ * bit allocator for blocks in the group simpler plus is allows a simple way to
+ * localise access to files and directories.
+ */
+typedef struct rtems_rfs_group_t
+{
+ /**
+ * Base block number.
+ */
+ rtems_rfs_buffer_block base;
+
+ /**
+ * The number of blocks in the group. Groups may be different sizes.
+ */
+ size_t size;
+
+ /**
+ * The block bitmap control.
+ */
+ rtems_rfs_bitmap_control block_bitmap;
+
+ /**
+ * The handle to the block bitmap buffer.
+ */
+ rtems_rfs_buffer_handle block_bitmap_buffer;
+
+ /**
+ * The inode bitmap control.
+ */
+ rtems_rfs_bitmap_control inode_bitmap;
+
+ /**
+ * The handle to the inode bitmap buffer.
+ */
+ rtems_rfs_buffer_handle inode_bitmap_buffer;
+
+} rtems_rfs_group;
+
+/**
+ * Return the disk's block for a block in a group.
+ */
+#define rtems_rfs_group_block(_g, _b) (((_g)->base) + (_b))
+
+/**
+ * Return the file system inode for a inode in a group.
+ */
+#define rtems_rfs_group_inode(_f, _g, _i) \
+ (((_f)->group_inodes * (_g)) + (_i) + RTEMS_RFS_ROOT_INO)
+
+/**
+ * Open a group. Allocate all the resources including the bitmaps.
+ *
+ * @param fs The file system.
+ * @param base The base block number.
+ * @param size The number of blocks in the group.
+ * @param group Reference to the group to open.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_group_open (rtems_rfs_file_system* fs,
+ rtems_rfs_buffer_block base,
+ size_t size,
+ size_t inodes,
+ rtems_rfs_group* group);
+
+/**
+ * Close a group. Release all resources the group holds.
+ *
+ * @param fs The file system.
+ * @param group The group to close.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_group_close (rtems_rfs_file_system* fs,
+ rtems_rfs_group* group);
+
+/**
+ * Allocate an inode or block. The groups are searched to find the next
+ * available inode or block.
+ *
+ * @param fs The file system data.
+ * @param goal The goal to seed the bitmap search.
+ * @param inode If true allocate an inode else allocate a block.
+ * @param result The allocated bit in the bitmap.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_group_bitmap_alloc (rtems_rfs_file_system* fs,
+ rtems_rfs_bitmap_bit goal,
+ bool inode,
+ rtems_rfs_bitmap_bit* result);
+
+/**
+ * Free the group allocated bit.
+ *
+ * @param fs The file system data.
+ * @param inode If true the number to free is an inode else it is a block.
+ * @prarm block The inode or block number to free.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_group_bitmap_free (rtems_rfs_file_system* fs,
+ bool inode,
+ rtems_rfs_bitmap_bit no);
+
+/**
+ * Test the group allocated bit.
+ *
+ * @param fs The file system data.
+ * @param inode If true the number to free is an inode else it is a block.
+ * @prarm block The inode or block number to free.
+ * @prarm state Return the state of the bit.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_group_bitmap_test (rtems_rfs_file_system* fs,
+ bool inode,
+ rtems_rfs_bitmap_bit no,
+ bool* state);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-inode.c b/cpukit/libfs/src/rfs/rtems-rfs-inode.c
new file mode 100644
index 0000000000..b23f09994d
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-inode.c
@@ -0,0 +1,370 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Inode Routines.
+ *
+ * These functions manage inodes in the RFS file system. An inode is part of a
+ * block that reside after the bitmaps in the group.
+ */
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+
+int
+rtems_rfs_inode_alloc (rtems_rfs_file_system* fs,
+ rtems_rfs_bitmap_bit goal,
+ rtems_rfs_ino* ino)
+{
+ rtems_rfs_bitmap_bit bit;
+ int rc;
+ rc = rtems_rfs_group_bitmap_alloc (fs, goal, true, &bit);
+ *ino = bit;
+ return rc;
+}
+
+int
+rtems_rfs_inode_free (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino)
+{
+ rtems_rfs_bitmap_bit bit;
+ bit = ino;
+ return rtems_rfs_group_bitmap_free (fs, true, bit);
+}
+
+int
+rtems_rfs_inode_open (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino,
+ rtems_rfs_inode_handle* handle,
+ bool load)
+{
+ int group;
+ int gino;
+ int index;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_OPEN))
+ printf ("rtems-rfs: inode-open: ino: %lu\n", ino);
+
+ if (ino == RTEMS_RFS_EMPTY_INO)
+ return EINVAL;
+
+ if ((ino - RTEMS_RFS_ROOT_INO) > rtems_rfs_fs_inodes (fs))
+ return EINVAL;
+
+ handle->ino = ino;
+ handle->node = NULL;
+ handle->loads = 0;
+
+ gino = ino - RTEMS_RFS_ROOT_INO;
+ group = gino / fs->group_inodes;
+ gino = gino % fs->group_inodes;
+ index = (gino / fs->inodes_per_block) + RTEMS_RFS_GROUP_INODE_BLOCK;
+
+ handle->offset = gino % fs->inodes_per_block;
+ handle->block = rtems_rfs_group_block (&fs->groups[group], index);
+
+ rc = rtems_rfs_buffer_handle_open (fs, &handle->buffer);
+ if ((rc == 0) && load)
+ rc = rtems_rfs_inode_load (fs, handle);
+ return rc;
+}
+
+int
+rtems_rfs_inode_close (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle)
+{
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_CLOSE))
+ printf ("rtems-rfs: inode-close: ino: %lu\n", handle->ino);
+
+ rc = rtems_rfs_inode_unload (fs, handle, true);
+
+ if ((rc == 0) && (handle->loads > 0))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_CLOSE))
+ printf ("rtems-rfs: inode-close: bad loads number: %d\n",
+ handle->loads);
+ rc = EIO;
+ }
+
+ handle->ino = 0;
+ return rc;
+}
+
+int
+rtems_rfs_inode_load (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle)
+{
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_LOAD))
+ printf ("rtems-rfs: inode-load: ino=%lu loads=%i loaded=%s\n",
+ handle->ino, handle->loads,
+ rtems_rfs_inode_is_loaded (handle) ? "yes" : "no");
+
+ /*
+ * An inode does not move so once loaded no need to do again.
+ */
+
+ if (!rtems_rfs_inode_is_loaded (handle))
+ {
+ int rc;
+
+ rc = rtems_rfs_buffer_handle_request (fs,&handle->buffer,
+ handle->block, true);
+ if (rc > 0)
+ return rc;
+
+ handle->node = rtems_rfs_buffer_data (&handle->buffer);
+ handle->node += handle->offset;
+ }
+
+ handle->loads++;
+
+ return 0;
+}
+
+int
+rtems_rfs_inode_unload (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle,
+ bool update_ctime)
+{
+ int rc = 0;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_UNLOAD))
+ printf ("rtems-rfs: inode-unload: ino=%lu loads=%i loaded=%s\n",
+ handle->ino, handle->loads,
+ rtems_rfs_inode_is_loaded (handle) ? "yes" : "no");
+
+ if (rtems_rfs_inode_is_loaded (handle))
+ {
+ if (handle->loads == 0)
+ return EIO;
+
+ handle->loads--;
+
+ if (handle->loads == 0)
+ {
+ /*
+ * If the buffer is dirty it will be release. Also set the ctime.
+ */
+ if (rtems_rfs_buffer_dirty (&handle->buffer) && update_ctime)
+ rtems_rfs_inode_set_ctime (handle, time (NULL));
+ rc = rtems_rfs_buffer_handle_release (fs, &handle->buffer);
+ handle->node = NULL;
+ }
+ }
+
+ return rc;
+}
+
+int
+rtems_rfs_inode_create (rtems_rfs_file_system* fs,
+ rtems_rfs_ino parent,
+ const char* name,
+ size_t length,
+ uint16_t mode,
+ uint16_t links,
+ uid_t uid,
+ gid_t gid,
+ rtems_rfs_ino* ino)
+{
+ rtems_rfs_inode_handle parent_inode;
+ rtems_rfs_inode_handle inode;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_INODE_CREATE))
+ {
+ const char* type = "unknown";
+ int c;
+ if (RTEMS_RFS_S_ISDIR (mode))
+ type = "dir";
+ else if (RTEMS_RFS_S_ISCHR (mode))
+ type = "char";
+ else if (RTEMS_RFS_S_ISBLK (mode))
+ type = "block";
+ else if (RTEMS_RFS_S_ISREG (mode))
+ type = "file";
+ else if (RTEMS_RFS_S_ISLNK (mode))
+ type = "link";
+ printf("rtems-rfs: inode-create: parent:%lu name:", parent);
+ for (c = 0; c < length; c++)
+ printf ("%c", name[c]);
+ printf (" type:%s mode:%04x (%03o)\n", type, mode, mode & ((1 << 10) - 1));
+ }
+
+ rc = rtems_rfs_inode_alloc (fs, parent, ino);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_inode_open (fs, *ino, &inode, true);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_inode_initialise (&inode, links, mode, uid, gid);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_inode_free (fs, *ino);
+ return rc;
+ }
+
+ /*
+ * Only handle the specifics of a directory. Let caller handle the others.
+ */
+ if (RTEMS_RFS_S_ISDIR (mode))
+ {
+ rc = rtems_rfs_dir_add_entry (fs, &inode, ".", 1, *ino);
+ if (rc == 0)
+ rc = rtems_rfs_dir_add_entry (fs, &inode, "..", 2, parent);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_delete (fs, &inode);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+ }
+
+ rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_delete (fs, &inode);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_dir_add_entry (fs, &parent_inode, name, length, *ino);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_delete (fs, &inode);
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_inode_close (fs, &parent_inode);
+ return rc;
+ }
+
+ /*
+ * If the node is a directory update the parent link count as the
+ * new directory has the '..' link that points to the parent.
+ */
+ if (RTEMS_RFS_S_ISDIR (mode))
+ rtems_rfs_inode_set_links (&parent_inode,
+ rtems_rfs_inode_get_links (&parent_inode) + 1);
+
+ rc = rtems_rfs_inode_close (fs, &parent_inode);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_delete (fs, &inode);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_free (fs, *ino);
+ return rc;
+ }
+
+ return 0;
+}
+
+int
+rtems_rfs_inode_delete (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle)
+{
+ int rc = 0;
+ if (rtems_rfs_inode_is_loaded (handle))
+ {
+ rtems_rfs_block_map map;
+
+ /*
+ * Free the ino number.
+ */
+ rc = rtems_rfs_inode_free (fs, handle->ino);
+ if (rc > 0)
+ return rc;
+
+ /*
+ * Free the blocks the inode may have attached.
+ */
+ rc = rtems_rfs_block_map_open (fs, handle, &map);
+ if (rc == 0)
+ {
+ int rrc;
+ rrc = rtems_rfs_block_map_free_all (fs, &map);
+ rc = rtems_rfs_block_map_close (fs, &map);
+ if (rc > 0)
+ rrc = rc;
+ memset (handle->node, 0xff, sizeof (rtems_rfs_inode));
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+ /*
+ * Do the release here to avoid the ctime field being set on a
+ * close. Also if there loads is greater then one then other loads
+ * active. Forcing the loads count to 0.
+ */
+ rc = rtems_rfs_buffer_handle_release (fs, &handle->buffer);
+ handle->loads = 0;
+ handle->node = NULL;
+ }
+ }
+ return rc;
+}
+
+int
+rtems_rfs_inode_initialise (rtems_rfs_inode_handle* handle,
+ uint16_t links,
+ uint16_t mode,
+ uid_t uid,
+ gid_t gid)
+{
+ int b;
+ rtems_rfs_inode_set_links (handle, links);
+ rtems_rfs_inode_set_flags (handle, 0);
+ rtems_rfs_inode_set_mode (handle, mode);
+ rtems_rfs_inode_set_uid_gid (handle, uid, gid);
+ rtems_rfs_inode_set_block_offset (handle, 0);
+ rtems_rfs_inode_set_block_count (handle, 0);
+ for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
+ rtems_rfs_inode_set_block (handle, b, 0);
+ rtems_rfs_inode_set_last_map_block (handle, 0);
+ rtems_rfs_inode_set_last_data_block (handle, 0);
+ return rtems_rfs_inode_time_stamp_now (handle, true, true);
+}
+
+int
+rtems_rfs_inode_time_stamp_now (rtems_rfs_inode_handle* handle,
+ bool atime,
+ bool mtime)
+{
+ time_t now;
+ if (!rtems_rfs_inode_is_loaded (handle))
+ return ENXIO;
+ now = time (NULL);
+ if (atime)
+ rtems_rfs_inode_set_atime (handle, now);
+ if (mtime)
+ rtems_rfs_inode_set_mtime (handle, now);
+ return 0;
+}
+
+rtems_rfs_pos
+rtems_rfs_inode_get_size (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle)
+{
+ rtems_rfs_block_size size;
+ size.count = rtems_rfs_inode_get_block_count (handle);
+ size.offset = rtems_rfs_inode_get_block_offset (handle);
+ return rtems_rfs_block_get_size (fs, &size);
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-inode.h b/cpukit/libfs/src/rfs/rtems-rfs-inode.h
new file mode 100644
index 0000000000..0a6226bd8c
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-inode.h
@@ -0,0 +1,688 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Information Node.
+ *
+ * The information nodes hold the data about all nodes in the file system.
+ */
+
+#if !defined (_RTEMS_RFS_INODE_H_)
+#define _RTEMS_RFS_INODE_H_
+
+#include <sys/stat.h>
+
+#include <rtems/rfs/rtems-rfs-data.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+
+/**
+ * The RFS mode definitions. Currently map to the C library ones.
+ */
+#define RTEMS_RFS_S_ISUID S_ISUID /**< Set user id on execution */
+#define RTEMS_RFS_S_ISGID S_ISGID /**< Set group id on execution */
+#define RTEMS_RFS_S_ISVTX S_ISVTX /**< Save swapped text even after use */
+#define RTEMS_RFS_S_IREAD S_IREAD /**< Read permission, owner */
+#define RTEMS_RFS_S_IWRITE S_IWRITE /**< Write permission, owner */
+#define RTEMS_RFS_S_IEXEC S_IEXEC /**< Execute/search permission, owner */
+#define RTEMS_RFS_S_ENFMT S_ENFMT /**< Enforcement-mode locking */
+#define RTEMS_RFS_S_IFMT S_IFMT /**< Type of file */
+#define RTEMS_RFS_S_IFDIR S_IFDIR /**< Directory */
+#define RTEMS_RFS_S_IFCHR S_IFCHR /**< Character special */
+#define RTEMS_RFS_S_IFBLK S_IFBLK /**< Block special */
+#define RTEMS_RFS_S_IFREG S_IFREG /**< Regular */
+#define RTEMS_RFS_S_IFLNK S_IFLNK /**< Symbolic link */
+#define RTEMS_RFS_S_IFSOCK S_IFSOCK /**< Socket */
+#define RTEMS_RFS_S_IFIFO S_IFIFO /**< Fifo */
+#define RTEMS_RFS_S_IRWXU S_IRWXU
+#define RTEMS_RFS_S_IRUSR S_IRUSR /**< Read permission, owner */
+#define RTEMS_RFS_S_IWUSR S_IWUSR /**< Write permission, owner */
+#define RTEMS_RFS_S_IXUSR S_IXUSR /**< Execute/search permission, owner */
+#define RTEMS_RFS_S_IRWXG S_IRWXG
+#define RTEMS_RFS_S_IRGRP S_IRGRP /**< Read permission, group */
+#define RTEMS_RFS_S_IWGRP S_IWGRP /**< Write permission, grougroup */
+#define RTEMS_RFS_S_IXGRP S_IXGRP /**< Execute/search permission, group */
+#define RTEMS_RFS_S_IRWXO S_IRWXO
+#define RTEMS_RFS_S_IROTH S_IROTH /**< Read permission, other */
+#define RTEMS_RFS_S_IWOTH S_IWOTH /**< Write permission, other */
+#define RTEMS_RFS_S_IXOTH S_IXOTH /**< Execute/search permission, other */
+
+#define RTEMS_RFS_S_ISBLK(m) S_ISBLK(m)
+#define RTEMS_RFS_S_ISCHR(m) S_ISCHR(m)
+#define RTEMS_RFS_S_ISDIR(m) S_ISDIR(m)
+#define RTEMS_RFS_S_ISFIFO(m) S_ISFIFO(m)
+#define RTEMS_RFS_S_ISREG(m) S_ISREG(m)
+#define RTEMS_RFS_S_ISLNK(m) S_ISLNK(m)
+#define RTEMS_RFS_S_ISSOCK(m) S_ISSOCK(m)
+
+/**
+ * Permissions of a symlink.
+ */
+#define RTEMS_RFS_S_SYMLINK \
+ RTEMS_RFS_S_IFLNK | RTEMS_RFS_S_IRWXU | RTEMS_RFS_S_IRWXG | RTEMS_RFS_S_IRWXO
+
+/**
+ * The inode number or ino.
+ */
+typedef uint32_t rtems_rfs_ino;
+
+/**
+ * The time in the file system.
+ */
+typedef uint32_t rtems_rfs_time;
+
+/**
+ * The size of a block value on disk. This include the inodes and indirect
+ * tables.
+ */
+typedef uint32_t rtems_rfs_inode_block;
+
+/**
+ * The size of the data name field in the inode.
+ */
+#define RTEMS_RFS_INODE_DATA_NAME_SIZE \
+ (RTEMS_RFS_INODE_BLOCKS * sizeof (rtems_rfs_inode_block))
+
+/**
+ * The inode.
+ */
+typedef struct rtems_rfs_inode_t
+{
+ /**
+ * The number of links to the inode.
+ */
+ uint16_t links;
+
+ /**
+ * The mode of the node.
+ */
+ uint16_t mode;
+
+ /**
+ * The owner of the node.
+ */
+ uint32_t owner;
+
+ /**
+ * Reserved.
+ */
+ uint16_t flags;
+
+ /**
+ * Amount of data held in the last block data.
+ */
+ uint16_t block_offset;
+
+ /**
+ * Number of blocks held by this file.
+ */
+ uint32_t block_count;
+
+ /**
+ * The access time. The last time the file was read.
+ */
+ rtems_rfs_time atime;
+
+ /**
+ * The modified time. The last time the file was written too.
+ */
+ rtems_rfs_time mtime;
+
+ /**
+ * The change time. The last time the inode was written too.
+ */
+ rtems_rfs_time ctime;
+
+ /**
+ * Blocks. These are the block numbers used by the node or table of
+ * nodes. The flags indicate the mode the blocks are being held in. In the
+ * direct table mode the blocks are entries in this table. In the indirect
+ * mode the blocks point to blocks that hold the block numbers. The data can
+ * also be a name if it fits. For example a symbolic link.
+ */
+ union
+ {
+ rtems_rfs_inode_block blocks[RTEMS_RFS_INODE_BLOCKS];
+ uint8_t name[RTEMS_RFS_INODE_DATA_NAME_SIZE];
+ } data;
+
+ /**
+ * The last block map block. Used as the goal when allocating a new block for
+ * use in the map.
+ */
+ rtems_rfs_inode_block last_map_block;
+
+ /**
+ * The last data block. Used as the goal when allocating a new block.
+ */
+ rtems_rfs_inode_block last_data_block;
+
+} rtems_rfs_inode;
+
+/**
+ * RFS Inode Handle.
+ */
+typedef struct rtems_rfs_inode_handle_t
+{
+ /**
+ * Handles can be linked as a list for easy processing.
+ */
+ rtems_chain_node link;
+
+ /**
+ * The ino for this handle.
+ */
+ rtems_rfs_ino ino;
+
+ /**
+ * The pointer to the inode.
+ */
+ rtems_rfs_inode* node;
+
+ /**
+ * The buffer that contains this inode.
+ */
+ rtems_rfs_buffer_handle buffer;
+
+ /**
+ * The block number that holds the inode.
+ */
+ rtems_rfs_buffer_block block;
+
+ /**
+ * The offset into the block for the inode.
+ */
+ int offset;
+
+ /**
+ * Number of load requests.
+ */
+ int loads;
+
+} rtems_rfs_inode_handle;
+
+/**
+ * Is the inode loaded ?
+ */
+#define rtems_rfs_inode_is_loaded(_h) ((_h)->node)
+
+/**
+ * Get the inode ino for a handle.
+ */
+#define rtems_rfs_inode_ino(_h) ((_h)->ino)
+
+/**
+ * Get the link count.
+ *
+ * @param handle The inode handle.
+ * @return uint16_t The link count.
+ */
+static inline uint16_t
+rtems_rfs_inode_get_links (rtems_rfs_inode_handle* handle)
+{
+ uint16_t links;
+ links = rtems_rfs_read_u16 (&handle->node->links);
+ if (links == 0xffff)
+ links = 0;
+ return links;
+}
+
+/**
+ * Set the link count.
+ *
+ * @param handle The inode handle.
+ * @prarm links The links.
+ */
+static inline void
+rtems_rfs_inode_set_links (rtems_rfs_inode_handle* handle, uint16_t links)
+{
+ rtems_rfs_write_u16 (&handle->node->links, links);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the flags.
+ *
+ * @param handle The inode handle.
+ * @return uint16_t The flags.
+ */
+static inline uint16_t
+rtems_rfs_inode_get_flags (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u16 (&handle->node->flags);
+}
+
+/**
+ * Set the flags.
+ *
+ * @param handle The inode handle.
+ * @prarm flags The flags.
+ */
+static inline void
+rtems_rfs_inode_set_flags (rtems_rfs_inode_handle* handle, uint16_t flags)
+{
+ rtems_rfs_write_u16 (&handle->node->flags, flags);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the mode.
+ *
+ * @param handle The inode handle.
+ * @return uint16_t The mode.
+ */
+static inline uint16_t
+rtems_rfs_inode_get_mode (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u16 (&handle->node->mode);
+}
+
+/**
+ * Set the mode.
+ *
+ * @param handle The inode handle.
+ * @prarm mode The mode.
+ */
+static inline void
+rtems_rfs_inode_set_mode (rtems_rfs_inode_handle* handle, uint16_t mode)
+{
+ rtems_rfs_write_u16 (&handle->node->mode, mode);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the user id.
+ *
+ * @param handle The inode handle.
+ * @return uint16_t The user id (uid).
+ */
+static inline uint16_t
+rtems_rfs_inode_get_uid (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->owner) & 0xffff;
+}
+
+/**
+ * Get the group id.
+ *
+ * @param handle The inode handle.
+ * @return uint16_t The group id (gid).
+ */
+static inline uint16_t
+rtems_rfs_inode_get_gid (rtems_rfs_inode_handle* handle)
+{
+ return (rtems_rfs_read_u32 (&handle->node->owner) >> 16) & 0xffff;
+}
+
+/**
+ * Set the user id and group id.
+ *
+ * @param handle The inode handle.
+ * @param uid The user id (uid).
+ * @param gid The group id (gid).
+ */
+static inline void
+rtems_rfs_inode_set_uid_gid (rtems_rfs_inode_handle* handle,
+ uint16_t uid, uint16_t gid)
+{
+ rtems_rfs_write_u32 (&handle->node->owner, (gid << 16) | uid);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the block offset.
+ *
+ * @param handle The inode handle.
+ * @return uint32_t The block offset.
+ */
+static inline uint16_t
+rtems_rfs_inode_get_block_offset (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u16 (&handle->node->block_offset);
+}
+
+/**
+ * Set the block offset.
+ *
+ * @param handle The inode handle.
+ * @param block_count The block offset.
+ */
+static inline void
+rtems_rfs_inode_set_block_offset (rtems_rfs_inode_handle* handle,
+ uint16_t block_offset)
+{
+ rtems_rfs_write_u16 (&handle->node->block_offset, block_offset);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the block count.
+ *
+ * @param handle The inode handle.
+ * @return uint32_t The block count.
+ */
+static inline uint32_t
+rtems_rfs_inode_get_block_count (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->block_count);
+}
+
+/**
+ * Set the block count.
+ *
+ * @param handle The inode handle.
+ * @param block_count The block count.
+ */
+static inline void
+rtems_rfs_inode_set_block_count (rtems_rfs_inode_handle* handle, uint32_t block_count)
+{
+ rtems_rfs_write_u32 (&handle->node->block_count, block_count);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the atime.
+ *
+ * @param handle The inode handle.
+ * @return rtems_rfs_time The atime.
+ */
+static inline rtems_rfs_time
+rtems_rfs_inode_get_atime (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->atime);
+}
+
+/**
+ * Set the atime.
+ *
+ * @param handle The inode handle.
+ * @prarm atime The atime.
+ */
+static inline void
+rtems_rfs_inode_set_atime (rtems_rfs_inode_handle* handle,
+ rtems_rfs_time atime)
+{
+ rtems_rfs_write_u32 (&handle->node->atime, atime);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the mtime.
+ *
+ * @param handle The inode handle.
+ * @return rtems_rfs_time The mtime.
+ */
+static inline rtems_rfs_time
+rtems_rfs_inode_get_mtime (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->mtime);
+}
+
+/**
+ * Set the mtime.
+ *
+ * @param handle The inode handle.
+ * @prarm atime The mtime.
+ */
+static inline void
+rtems_rfs_inode_set_mtime (rtems_rfs_inode_handle* handle,
+ rtems_rfs_time mtime)
+{
+ rtems_rfs_write_u32 (&handle->node->mtime, mtime);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the ctime.
+ *
+ * @param handle The inode handle.
+ * @return rtems_rfs_time The ctime.
+ */
+static inline rtems_rfs_time
+rtems_rfs_inode_get_ctime (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->ctime);
+}
+
+/**
+ * Set the ctime.
+ *
+ * @param handle The inode handle.
+ * @prarm atime The ctime.
+ */
+static inline void
+rtems_rfs_inode_set_ctime (rtems_rfs_inode_handle* handle,
+ rtems_rfs_time ctime)
+{
+ rtems_rfs_write_u32 (&handle->node->ctime, ctime);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the block number.
+ *
+ * @param handle The inode handle.
+ * @param block The block number to return.
+ * @return uint32_t The block number.
+ */
+static inline uint32_t
+rtems_rfs_inode_get_block (rtems_rfs_inode_handle* handle, int block)
+{
+ return rtems_rfs_read_u32 (&handle->node->data.blocks[block]);
+}
+
+/**
+ * Set the block number for a given block index.
+ *
+ * @param handle The inode handle.
+ * @param block The block index.
+ * @param bno The block number.
+ */
+static inline void
+rtems_rfs_inode_set_block (rtems_rfs_inode_handle* handle, int block, uint32_t bno)
+{
+ rtems_rfs_write_u32 (&handle->node->data.blocks[block], bno);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the last map block from the inode.
+ *
+ * @param handle The inode handle.
+ * @return uint32_t The last map block number.
+ */
+static inline uint32_t
+rtems_rfs_inode_get_last_map_block (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->last_map_block);
+}
+
+/**
+ * Set the last map block.
+ *
+ * @param handle The inode handle.
+ * @param block_count The last map block number.
+ */
+static inline void
+rtems_rfs_inode_set_last_map_block (rtems_rfs_inode_handle* handle, uint32_t last_map_block)
+{
+ rtems_rfs_write_u32 (&handle->node->last_map_block, last_map_block);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Get the last data block from the inode.
+ *
+ * @param handle The inode handle.
+ * @return uint32_t The last data block number.
+ */
+static inline uint32_t
+rtems_rfs_inode_get_last_data_block (rtems_rfs_inode_handle* handle)
+{
+ return rtems_rfs_read_u32 (&handle->node->last_data_block);
+}
+
+/**
+ * Set the last data block.
+ *
+ * @param handle The inode handle.
+ * @param block_count The last data block number.
+ */
+static inline void
+rtems_rfs_inode_set_last_data_block (rtems_rfs_inode_handle* handle, uint32_t last_data_block)
+{
+ rtems_rfs_write_u32 (&handle->node->last_data_block, last_data_block);
+ rtems_rfs_buffer_mark_dirty (&handle->buffer);
+}
+
+/**
+ * Allocate an inode number and return it.
+ *
+ * @param fs The file system data.
+ * @param ino Return the ino.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_alloc (rtems_rfs_file_system* fs,
+ rtems_rfs_bitmap_bit goal,
+ rtems_rfs_ino* ino);
+
+/**
+ * Allocate an inode number and return it.
+ *
+ * @param fs The file system data.
+ * @param ino The ino too free.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_free (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino);
+
+/**
+ * Open the inode handle. This reads the inode into the buffer and sets the
+ * data pointer. All data is in media byte order and needs to be accessed via
+ * the supporting calls.
+ *
+ * @param fs The file system.
+ * @parma ino The inode number.
+ * @param handle The handle to the inode we are opening.
+ * @param load If true load the inode into memory from the media.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_open (rtems_rfs_file_system* fs,
+ rtems_rfs_ino ino,
+ rtems_rfs_inode_handle* handle,
+ bool load);
+
+/**
+ * The close inode handle. All opened inodes need to be closed.
+ *
+ * @param fs The file system.
+ * @param handle The handle to close.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_close (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle);
+
+/**
+ * Load the inode into memory.
+ *
+ * @param fs The file system.
+ * @param handle The inode handle to load.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_load (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle);
+
+/**
+ * Unload the inode from memory.
+ *
+ * @param fs The file system.
+ * @param handle The inode handle to unload.
+ * @param update_ctime Update the ctime field of the inode.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_unload (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle,
+ bool update_ctime);
+
+/**
+ * Create an inode allocating, initialising and adding an entry to the parent
+ * directory.
+ *
+ * @param fs The file system data.
+ * @param parent The parent inode number to add the directory entry to.
+ * @param name The name of the directory entryinode to create.
+ *
+ */
+int rtems_rfs_inode_create (rtems_rfs_file_system* fs,
+ rtems_rfs_ino parent,
+ const char* name,
+ size_t length,
+ uint16_t mode,
+ uint16_t links,
+ uid_t uid,
+ gid_t gid,
+ rtems_rfs_ino* ino);
+
+/**
+ * Delete the inode eraseing it and release the buffer to commit the write. You
+ * need to load the inode again if you wish to use it again.
+ *
+ * @param fs The file system.
+ * @param handle The inode handle to erase.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_delete (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle);
+
+/**
+ * Initialise a new inode.
+ *
+ * @param handle The inode handle to initialise.
+ * @param links The number of links to the inode.
+ * @param mode The inode mode.
+ * @param uid The user id.
+ * @param gid The group id.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_inode_initialise (rtems_rfs_inode_handle* handle,
+ uint16_t links,
+ uint16_t mode,
+ uid_t uid,
+ gid_t gid);
+
+/**
+ * Time stamp the inode with the current time. The ctime field is hanlded
+ * automatically.
+ *
+ * @param handle The inode handle.
+ * @param atime Update the atime field.
+ * @param mtime UPdate the mtime field.
+ * @return int The error number (errno). No error if 0 and ENXIO if no inode
+ * loaded.
+ */
+int rtems_rfs_inode_time_stamp_now (rtems_rfs_inode_handle* handle,
+ bool atime,
+ bool mtime);
+
+/**
+ * Calculate the size of data attached to the inode.
+ *
+ * @param fs The file system data.
+ * @oaram handle The inode handle.
+ * @return rtems_rfs_pos The data size in bytes in the block map attched to the
+ * inode.
+ */
+rtems_rfs_pos rtems_rfs_inode_get_size (rtems_rfs_file_system* fs,
+ rtems_rfs_inode_handle* handle);
+
+#endif
+
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-link.c b/cpukit/libfs/src/rfs/rtems-rfs-link.c
new file mode 100644
index 0000000000..bfbcae66e7
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-link.c
@@ -0,0 +1,439 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Link Routines.
+ *
+ * These functions manage links. A link is the addition of a directory entry in
+ * a parent directory and incrementing the links count in the inode.
+ */
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+#include <rtems/rfs/rtems-rfs-dir-hash.h>
+
+int
+rtems_rfs_link (rtems_rfs_file_system* fs,
+ const char* name,
+ int length,
+ rtems_rfs_ino parent,
+ rtems_rfs_ino target)
+{
+ rtems_rfs_inode_handle parent_inode;
+ rtems_rfs_inode_handle target_inode;
+ uint16_t links;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_LINK))
+ {
+ int c;
+ printf ("rtems-rfs: link: parent(%lu) -> ", parent);
+ for (c = 0; c < length; c++)
+ printf ("%c", name[c]);
+ printf ("(%lu)\n", target);
+ }
+
+ rc = rtems_rfs_inode_open (fs, target, &target_inode, true);
+ if (rc)
+ return rc;
+
+ if (S_ISDIR (rtems_rfs_inode_get_mode (&target_inode)))
+ {
+ rtems_rfs_inode_close (fs, &target_inode);
+ return ENOTSUP;
+ }
+
+ rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
+ if (rc)
+ {
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_dir_add_entry (fs, &parent_inode, name, length, target);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &parent_inode);
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ links = rtems_rfs_inode_get_links (&target_inode) + 1;
+ rtems_rfs_inode_set_links (&target_inode, links);
+
+ rc = rtems_rfs_inode_time_stamp_now (&parent_inode, true, true);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &parent_inode);
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_close (fs, &parent_inode);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_close (fs, &target_inode);
+
+ return rc;
+}
+
+int
+rtems_rfs_unlink (rtems_rfs_file_system* fs,
+ rtems_rfs_ino parent,
+ rtems_rfs_ino target,
+ uint32_t doff,
+ bool dir)
+{
+ rtems_rfs_inode_handle parent_inode;
+ rtems_rfs_inode_handle target_inode;
+ uint16_t links;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: unlink: parent(%lu) -X-> (%lu)\n", parent, target);
+
+ rc = rtems_rfs_inode_open (fs, target, &target_inode, true);
+ if (rc)
+ return rc;
+
+ if (dir)
+ {
+ rc = rtems_rfs_dir_empty (fs, &target_inode);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: dir-empty: %d: %s\n", rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+ }
+ else
+ {
+ /*
+ * Directories not allowed and the target is a directory.
+ */
+ if (RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&target_inode)))
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: link is a directory\n");
+ rtems_rfs_inode_close (fs, &target_inode);
+ return EISDIR;
+ }
+ }
+
+ rc = rtems_rfs_inode_open (fs, parent, &parent_inode, true);
+ if (rc)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: link: inode-open failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_dir_del_entry (fs, &parent_inode, target, doff);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: unlink: dir-del failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &parent_inode);
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ links = rtems_rfs_inode_get_links (&target_inode);
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: unlink: target:%lu links:%u\n", target, links);
+
+ if (links > 1)
+ {
+ links--;
+ rtems_rfs_inode_set_links (&target_inode, links);
+ }
+ else
+ {
+ /*
+ * Erasing the inode releases all blocks attached to it.
+ */
+ rc = rtems_rfs_inode_delete (fs, &target_inode);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: unlink: inode-del failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &parent_inode);
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ if (dir)
+ {
+ links = rtems_rfs_inode_get_links (&parent_inode);
+ if (links > 1)
+ links--;
+ rtems_rfs_inode_set_links (&parent_inode, links);
+ }
+ }
+
+ rc = rtems_rfs_inode_time_stamp_now (&parent_inode, true, true);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: link: inode-time-stamp failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &parent_inode);
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_close (fs, &parent_inode);
+ if (rc > 0)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: link: parent inode-close failed: %d: %s\n",
+ rc, strerror (rc));
+ rtems_rfs_inode_close (fs, &target_inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_inode_close (fs, &target_inode);
+
+ if ((rc > 0) && rtems_rfs_trace (RTEMS_RFS_TRACE_UNLINK))
+ printf ("rtems-rfs: link: target inode-close failed: %d: %s\n",
+ rc, strerror (rc));
+
+ return rc;
+}
+
+int
+rtems_rfs_symlink (rtems_rfs_file_system* fs,
+ const char* name,
+ int length,
+ const char* link,
+ int link_length,
+ uid_t uid,
+ gid_t gid,
+ rtems_rfs_ino parent)
+{
+ rtems_rfs_inode_handle inode;
+ rtems_rfs_ino ino;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK))
+ {
+ int c;
+ printf ("rtems-rfs: symlink: parent:%lu name:", parent);
+ for (c = 0; c < length; c++)
+ printf ("%c", name[c]);
+ printf (" link:");
+ for (c = 0; c < link_length; c++)
+ printf ("%c", link[c]);
+ }
+
+ if (link_length >= rtems_rfs_fs_block_size (fs))
+ return ENAMETOOLONG;
+
+ rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
+ RTEMS_RFS_S_SYMLINK,
+ 1, uid, gid, &ino);
+ if (rc > 0)
+ return rc;
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ return rc;
+
+ /*
+ * If the link length is less than the length of data union in the inode
+ * place the link into the data area else allocate a block and write the link
+ * to that.
+ */
+ if (link_length < RTEMS_RFS_INODE_DATA_NAME_SIZE)
+ {
+ memset (inode.node->data.name, 0, RTEMS_RFS_INODE_DATA_NAME_SIZE);
+ memcpy (inode.node->data.name, link, link_length);
+ rtems_rfs_inode_set_block_count (&inode, 0);
+ }
+ else
+ {
+ rtems_rfs_block_map map;
+ rtems_rfs_block_no block;
+ rtems_rfs_buffer_handle buffer;
+ uint8_t* data;
+
+ rc = rtems_rfs_block_map_open (fs, &inode, &map);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_block_map_grow (fs, &map, 1, &block);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ data = rtems_rfs_buffer_data (&buffer);
+
+ memset (data, 0xff, rtems_rfs_fs_block_size (fs));
+ memcpy (data, link, link_length);
+
+ rc = rtems_rfs_buffer_handle_close (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_block_map_close (fs, &map);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+ }
+
+ rtems_rfs_inode_set_block_offset (&inode, link_length);
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+
+ return rc;
+}
+
+int
+rtems_rfs_symlink_read (rtems_rfs_file_system* fs,
+ rtems_rfs_ino link,
+ char* path,
+ size_t size,
+ size_t* length)
+{
+ rtems_rfs_inode_handle inode;
+ int rc;
+
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_SYMLINK_READ))
+ printf ("rtems-rfs: symlink-read: link:%lu\n", link);
+
+ rc = rtems_rfs_inode_open (fs, link, &inode, true);
+ if (rc)
+ return rc;
+
+ if (!RTEMS_RFS_S_ISLNK (rtems_rfs_inode_get_mode (&inode)))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ return EINVAL;
+ }
+
+ *length = rtems_rfs_inode_get_block_offset (&inode);
+
+ if (size < *length)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ return EINVAL;
+ }
+
+ if (rtems_rfs_inode_get_block_count (&inode) == 0)
+ {
+ memcpy (path, inode.node->data.name, *length);
+ }
+ else
+ {
+ rtems_rfs_block_map map;
+ rtems_rfs_block_no block;
+ rtems_rfs_buffer_handle buffer;
+ char* data;
+
+ rc = rtems_rfs_block_map_open (fs, &inode, &map);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_block_map_seek (fs, &map, 0, &block);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, false);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ data = rtems_rfs_buffer_data (&buffer);
+ memcpy (path, data, *length);
+
+ rc = rtems_rfs_buffer_handle_close (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_block_map_close (fs, &map);
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+
+ rc = rtems_rfs_block_map_close (fs, &map);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ return rc;
+ }
+ }
+
+ path[*length] = '\0';
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+
+ return rc;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-link.h b/cpukit/libfs/src/rfs/rtems-rfs-link.h
new file mode 100644
index 0000000000..d80db0195c
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-link.h
@@ -0,0 +1,99 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Link Support
+ *
+ * This file provides the link support functions.
+ */
+
+#if !defined (_RTEMS_RFS_LINK_H_)
+#define _RTEMS_RFS_LINK_H_
+
+#include <dirent.h>
+
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+
+/**
+ * Create a link.
+ *
+ * @param fs The file system.
+ * @param name The name of the link.
+ * @param length The length of the name.
+ * @param parent The inode number of the parent directory.
+ * @param target The inode of the target.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_link (rtems_rfs_file_system* fs,
+ const char* name,
+ int length,
+ rtems_rfs_ino parent,
+ rtems_rfs_ino target);
+
+/**
+ * Unlink the node from the parent directory. A directory offset for the target
+ * entry is required because links cause a number of inode numbers to appear in
+ * a single directory so scanning does not work.
+ *
+ * @param fs The file system.
+ * @param parent The inode number of the parent directory.
+ * @param target The inode of the target.
+ * @param doff Parent directory entry offset for the target entry.
+ * @param dir If true unlinking of directory nodes is allowed.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_unlink (rtems_rfs_file_system* fs,
+ rtems_rfs_ino parent,
+ rtems_rfs_ino target,
+ uint32_t doff,
+ bool dir);
+
+/**
+ * Symbolic link is an inode that has a path attached.
+ *
+ * @param fs The file system data.
+ * @param name The name of the node.
+ * @param length The length of the name of the node.
+ * @param link The link path attached to the symlink inode.
+ * @param link_length The length of the link path.
+ * @param parent The parent inode number.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_symlink (rtems_rfs_file_system* fs,
+ const char* name,
+ int length,
+ const char* link,
+ int link_length,
+ uid_t uid,
+ gid_t gid,
+ rtems_rfs_ino parent);
+
+/**
+ * Read a symbolic link into the provided buffer returning the link of link
+ * name.
+ *
+ * @param fs The file system data.
+ * @param link The link inode number to read.
+ * @param path The buffer to write the link path into.
+ * @param size The size of the buffer.
+ * @param length Set to the length of the link path.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_symlink_read (rtems_rfs_file_system* fs,
+ rtems_rfs_ino link,
+ char* path,
+ size_t size,
+ size_t* length);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-mutex.c b/cpukit/libfs/src/rfs/rtems-rfs-mutex.c
new file mode 100644
index 0000000000..e67651d269
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-mutex.c
@@ -0,0 +1,68 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Mutex.
+ */
+
+#include <rtems/rfs/rtems-rfs-mutex.h>
+
+#if __rtems__
+/**
+ * RTEMS_RFS Mutex Attributes
+ *
+ * @warning Do not configure as inherit priority. If a driver is in the driver
+ * initialisation table this locked semaphore will have the IDLE task
+ * as the holder and a blocking task will raise the priority of the
+ * IDLE task which can cause unsual side effects like not work.
+ */
+#define RTEMS_RFS_MUTEX_ATTRIBS \
+ (RTEMS_PRIORITY | RTEMS_SIMPLE_BINARY_SEMAPHORE | \
+ RTEMS_NO_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
+#endif
+
+int
+rtems_rfs_mutex_create (rtems_rfs_mutex* mutex)
+{
+#if __rtems__
+ rtems_status_code sc;
+ sc = rtems_semaphore_create (rtems_build_name ('R', 'F', 'S', 'm'),
+ 1, RTEMS_RFS_MUTEX_ATTRIBS, 0,
+ mutex);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_MUTEX))
+ printf ("rtems-rfs: mutex: open failed: %s\n",
+ rtems_status_text (sc));
+ return EIO;
+ }
+#endif
+ return 0;
+}
+
+int
+rtems_rfs_mutex_destroy (rtems_rfs_mutex* mutex)
+{
+#if __rtems__
+ rtems_status_code sc;
+ sc = rtems_semaphore_delete (*mutex);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_MUTEX))
+ printf ("rtems-rfs: mutex: close failed: %s\n",
+ rtems_status_text (sc));
+ return EIO;
+ }
+#endif
+ return 0;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-mutex.h b/cpukit/libfs/src/rfs/rtems-rfs-mutex.h
new file mode 100644
index 0000000000..12e7fee921
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-mutex.h
@@ -0,0 +1,108 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Mutex.
+ *
+ * It may be suprising we abstract this for the RTEMS file system but this code
+ * is designed to be run on host operating systems.
+ */
+
+#if !defined (_RTEMS_RFS_MUTEX_H_)
+#define _RTEMS_RFS_MUTEX_H_
+
+#include <errno.h>
+
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+#if __rtems__
+#include <rtems.h>
+#include <rtems/error.h>
+#endif
+
+/**
+ * RFS Mutex type.
+ */
+#if __rtems__
+typedef rtems_id rtems_rfs_mutex;
+#else
+typedef uint32_t rtems_rfs_mutex; /* place holder */
+#endif
+
+/**
+ * Create the mutex.
+ *
+ * @param mutex Reference to the mutex handle returned to the caller.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_mutex_create (rtems_rfs_mutex* mutex);
+
+/**
+ * Create the mutex.
+ *
+ * @param mutex Reference to the mutex handle returned to the caller.
+ * @return int The error number (errno). No error if 0.
+ */
+int rtems_rfs_mutex_destroy (rtems_rfs_mutex* mutex);
+
+/**
+ * Lock the mutex.
+ *
+ * @param mutex The mutex to lock.
+ * @retval true The mutex is locked.
+ * @retval false The mutex could not be locked.
+ */
+static inline int
+rtems_rfs_mutex_lock (rtems_rfs_mutex* mutex)
+{
+#if __rtems__
+ rtems_status_code sc = rtems_semaphore_obtain (*mutex, RTEMS_WAIT, 0);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+#if RTEMS_RFS_TRACE
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_MUTEX))
+ printf ("rtems-rfs: mutex: obtain failed: %s\n",
+ rtems_status_text (sc));
+#endif
+ return EIO;
+ }
+#endif
+ return 0;
+}
+
+/**
+ * Unlock the mutex.
+ *
+ * @param mutex The mutex to unlock.
+ * @retval true The mutex is unlocked.
+ * @retval false The mutex could not be unlocked.
+ */
+static inline int
+rtems_rfs_mutex_unlock (rtems_rfs_mutex* mutex)
+{
+#if __rtems__
+ rtems_status_code sc = rtems_semaphore_release (*mutex);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+#if RTEMS_RFS_TRACE
+ if (rtems_rfs_trace (RTEMS_RFS_TRACE_MUTEX))
+ printf ("rtems-rfs: mutex: release failed: %s\n",
+ rtems_status_text (sc));
+#endif
+ return EIO;
+ }
+#endif
+ return 0;
+}
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems-dev.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems-dev.c
new file mode 100644
index 0000000000..cebd730ed7
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems-dev.c
@@ -0,0 +1,271 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS RFS Device Interface.
+ *
+ * This file contains the set of handlers used to map operations on RFS device
+ * nodes onto calls to the RTEMS Classic API IO Manager.
+ *
+ */
+
+#include "rtems-rfs-rtems.h"
+
+/*
+ * Convert RTEMS status to a UNIX errno
+ */
+extern int rtems_deviceio_errno (rtems_status_code code);
+
+/**
+ * This handler maps an open() operation onto rtems_io_open().
+ *
+ * @param iop
+ * @param pathname
+ * @param flag
+ * @param mode
+ * @return int
+ */
+static int
+rtems_rfs_rtems_device_open ( rtems_libio_t *iop,
+ const char *pathname,
+ uint32_t flag,
+ uint32_t mode)
+{
+ rtems_libio_open_close_args_t args;
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (&iop->pathinfo);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_iop_ino (iop);
+ rtems_rfs_inode_handle inode;
+ int major;
+ int minor;
+ rtems_status_code status;
+ int rc;
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("device_open: opening inode", rc);
+ }
+
+ major = rtems_rfs_inode_get_block (&inode, 0);
+ minor = rtems_rfs_inode_get_block (&inode, 1);
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("device_open: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ iop->data0 = major;
+ iop->data1 = (void*)((intptr_t) minor);
+
+ args.iop = iop;
+ args.flags = iop->flags;
+ args.mode = mode;
+
+ status = rtems_io_open (major, minor, (void *) &args);
+ if (status)
+ return rtems_deviceio_errno(status);
+
+ return 0;
+}
+
+/**
+ * This handler maps a close() operation onto rtems_io_close().
+ *
+ * @param iop
+ * @return int
+ */
+
+static int
+rtems_rfs_rtems_device_close (rtems_libio_t* iop)
+{
+ rtems_libio_open_close_args_t args;
+ rtems_status_code status;
+ int major;
+ int minor;
+
+ major = (int) iop->data0;
+ minor = (intptr_t) iop->data1;
+
+ args.iop = iop;
+ args.flags = 0;
+ args.mode = 0;
+
+ status = rtems_io_close (major, minor, (void *) &args);
+ if (status)
+ return rtems_deviceio_errno (status);
+
+ return 0;
+}
+
+/**
+ * This handler maps a read() operation onto rtems_io_read().
+ *
+ * @param iop
+ * @param buffer
+ * @param count
+ * @return ssize_t
+ */
+
+static ssize_t
+rtems_rfs_rtems_device_read (rtems_libio_t* iop, void* buffer, size_t count)
+{
+ rtems_libio_rw_args_t args;
+ rtems_status_code status;
+ int major;
+ int minor;
+
+ major = (int) iop->data0;
+ minor = (intptr_t) iop->data1;
+
+ args.iop = iop;
+ args.offset = iop->offset;
+ args.buffer = buffer;
+ args.count = count;
+ args.flags = iop->flags;
+ args.bytes_moved = 0;
+
+ status = rtems_io_read (major, minor, (void *) &args);
+ if (status)
+ return rtems_deviceio_errno (status);
+
+ return (ssize_t) args.bytes_moved;
+}
+
+/*
+ * This handler maps a write() operation onto rtems_io_write().
+ *
+ * @param iop
+ * @param buffer
+ * @param count
+ * @return ssize_t
+ */
+
+static ssize_t
+rtems_rfs_rtems_device_write (rtems_libio_t* iop,
+ const void* buffer,
+ size_t count)
+{
+ rtems_libio_rw_args_t args;
+ rtems_status_code status;
+ int major;
+ int minor;
+
+ major = (int) iop->data0;
+ minor = (intptr_t) iop->data1;
+
+ args.iop = iop;
+ args.offset = iop->offset;
+ args.buffer = (void *) buffer;
+ args.count = count;
+ args.flags = iop->flags;
+ args.bytes_moved = 0;
+
+ status = rtems_io_write (major, minor, (void *) &args);
+ if (status)
+ return rtems_deviceio_errno (status);
+
+ return (ssize_t) args.bytes_moved;
+}
+
+/**
+ * This handler maps an ioctl() operation onto rtems_io_ioctl().
+ *
+ * @param iop
+ * @param command
+ * @param buffer
+ * @return int
+ */
+
+static int
+rtems_rfs_rtems_device_ioctl (rtems_libio_t* iop,
+ uint32_t command,
+ void* buffer)
+{
+ rtems_libio_ioctl_args_t args;
+ rtems_status_code status;
+ int major;
+ int minor;
+
+ major = (int) iop->data0;
+ minor = (intptr_t) iop->data1;
+
+ args.iop = iop;
+ args.command = command;
+ args.buffer = buffer;
+
+ status = rtems_io_control (major, minor, (void *) &args);
+ if (status)
+ return rtems_deviceio_errno (status);
+
+ return args.ioctl_return;
+}
+
+/**
+ * This handler eats all lseek() operations and does not create an error. It
+ * assumes all devices can handle the seek. The writes fail.
+ *
+ * @param iop
+ * @param offset
+ * @param whence
+ * @return rtems_off64_t
+ */
+
+static rtems_off64_t
+rtems_rfs_rtems_device_lseek (rtems_libio_t* iop,
+ rtems_off64_t offset,
+ int whence)
+{
+ return offset;
+}
+
+/**
+ * The consumes the truncate call. You cannot truncate device files.
+ *
+ * @param iop
+ * @param length
+ * @return int
+ */
+
+static int
+rtems_rfs_rtems_device_ftruncate (rtems_libio_t* iop, rtems_off64_t length)
+{
+ return 0;
+}
+
+/*
+ * Handler table for RFS device nodes
+ */
+
+const rtems_filesystem_file_handlers_r rtems_rfs_rtems_device_handlers = {
+ .open_h = rtems_rfs_rtems_device_open,
+ .close_h = rtems_rfs_rtems_device_close,
+ .read_h = rtems_rfs_rtems_device_read,
+ .write_h = rtems_rfs_rtems_device_write,
+ .ioctl_h = rtems_rfs_rtems_device_ioctl,
+ .lseek_h = rtems_rfs_rtems_device_lseek,
+ .fstat_h = rtems_rfs_rtems_stat,
+ .fchmod_h = rtems_rfs_rtems_fchmod,
+ .ftruncate_h = rtems_rfs_rtems_device_ftruncate,
+ .fpathconf_h = NULL,
+ .fsync_h = NULL,
+ .fdatasync_h = NULL,
+ .fcntl_h = NULL,
+ .rmnod_h = rtems_rfs_rtems_rmnod
+};
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c
new file mode 100644
index 0000000000..f22e3d6913
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems-dir.c
@@ -0,0 +1,238 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS RFS Directory Access Routines
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <rtems/rfs/rtems-rfs-dir.h>
+#include <rtems/rfs/rtems-rfs-link.h>
+#include "rtems-rfs-rtems.h"
+
+/**
+ * This rountine will verify that the node being opened as a directory is in
+ * fact a directory node. If it is then the offset into the directory will be
+ * set to 0 to position to the first directory entry.
+ *
+ * @param iop
+ * @param pathname
+ * @param flag
+ * @param mode
+ * @@return int
+ */
+static int
+rtems_rfs_rtems_dir_open (rtems_libio_t* iop,
+ const char* pathname,
+ uint32_t flag,
+ uint32_t mode)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (&iop->pathinfo);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_iop_ino (iop);
+ rtems_rfs_inode_handle inode;
+ int rc;
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("dir_open: opening inode", rc);
+ }
+
+ if (!RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("dir_open: not dir", ENOTDIR);
+ }
+
+ iop->offset = 0;
+
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/**
+ * This routine will be called by the generic close routine to cleanup any
+ * resources that have been allocated for the management of the file
+ *
+ * @param iop
+ * @retval 0 Always no error.
+ */
+static int
+rtems_rfs_rtems_dir_close (rtems_libio_t* iop)
+{
+ /*
+ * The RFS does not hold any resources. Nothing to do.
+ */
+ return 0;
+}
+
+/**
+ * This routine will read the next directory entry based on the directory
+ * offset. The offset should be equal to -n- time the size of an individual
+ * dirent structure. If n is not an integer multiple of the sizeof a dirent
+ * structure, an integer division will be performed to determine directory
+ * entry that will be returned in the buffer. Count should reflect -m- times
+ * the sizeof dirent bytes to be placed in the buffer. If there are not -m-
+ * dirent elements from the current directory position to the end of the
+ * exisiting file, the remaining entries will be placed in the buffer and the
+ * returned value will be equal to -m actual- times the size of a directory
+ * entry.
+ */
+static ssize_t
+rtems_rfs_rtems_dir_read (rtems_libio_t* iop,
+ void* buffer,
+ size_t count)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (&iop->pathinfo);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_iop_ino (iop);
+ rtems_rfs_inode_handle inode;
+ struct dirent* dirent;
+ size_t bytes_transfered;
+ int d;
+ int rc;
+
+ count = count / sizeof (struct dirent);
+ dirent = buffer;
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("dir_read: read inode", rc);
+ }
+
+ bytes_transfered = 0;
+
+ for (d = 0; d < count; d++, dirent++)
+ {
+ size_t size;
+ rc = rtems_rfs_dir_read (fs, &inode, iop->offset, dirent, &size);
+ if (rc == ENOENT)
+ {
+ rc = 0;
+ break;
+ }
+ if (rc > 0)
+ {
+ bytes_transfered = rtems_rfs_rtems_error ("dir_read: dir read", rc);
+ break;
+ }
+ iop->offset += size;
+ bytes_transfered += sizeof (struct dirent);
+ }
+
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+
+ return (ssize_t) bytes_transfered;
+}
+
+/**
+ * This routine will behave in one of three ways based on the state of argument
+ * whence. Based on the state of its value the offset argument will be
+ * interpreted using one of the following methods:
+ *
+ * SEEK_SET - offset is the absolute byte offset from the start of the
+ * logical start of the dirent sequence that represents the
+ * directory
+ * SEEK_CUR - offset is used as the relative byte offset from the current
+ * directory position index held in the iop structure
+ * SEEK_END - N/A --> This will cause an assert.
+ *
+ * @param iop
+ * @param offset
+ * @param whence
+ * return rtems_off64_t
+ */
+static rtems_off64_t
+rtems_rfs_rtems_dir_lseek (rtems_libio_t* iop,
+ rtems_off64_t offset,
+ int whence)
+{
+ switch (whence)
+ {
+ case SEEK_SET: /* absolute move from the start of the file */
+ case SEEK_CUR: /* relative move */
+ break;
+
+ case SEEK_END: /* Movement past the end of the directory via lseek */
+ /* is not a permitted operation */
+ default:
+ return rtems_rfs_rtems_error ("dir_lseek: bad whence", EINVAL);
+ break;
+ }
+ return 0;
+}
+
+static int
+rtems_rfs_rtems_dir_rmnod (rtems_filesystem_location_info_t* parent_pathloc,
+ rtems_filesystem_location_info_t* pathloc)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino parent = rtems_rfs_rtems_get_pathloc_ino (parent_pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ uint32_t doff = rtems_rfs_rtems_get_pathloc_doff (pathloc);
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_DIR_RMNOD))
+ printf ("rtems-rfs: dir-rmnod: parent:%ld doff:%lu, ino:%ld\n",
+ parent, doff, ino);
+
+ if (ino == RTEMS_RFS_ROOT_INO)
+ return rtems_rfs_rtems_error ("dir_rmnod: root inode", EBUSY);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_unlink (fs, parent, ino, doff, true);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("dir_rmnod: unlinking", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/*
+ * Set of operations handlers for operations on directories.
+ */
+
+const rtems_filesystem_file_handlers_r rtems_rfs_rtems_dir_handlers = {
+ .open_h = rtems_rfs_rtems_dir_open,
+ .close_h = rtems_rfs_rtems_dir_close,
+ .read_h = rtems_rfs_rtems_dir_read,
+ .write_h = NULL,
+ .ioctl_h = NULL,
+ .lseek_h = rtems_rfs_rtems_dir_lseek,
+ .fstat_h = rtems_rfs_rtems_stat,
+ .fchmod_h = rtems_rfs_rtems_fchmod,
+ .ftruncate_h = NULL,
+ .fpathconf_h = NULL,
+ .fsync_h = NULL,
+ .fdatasync_h = rtems_rfs_rtems_fdatasync,
+ .fcntl_h = rtems_rfs_rtems_fcntl,
+ .rmnod_h = rtems_rfs_rtems_dir_rmnod
+};
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems-file.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems-file.c
new file mode 100644
index 0000000000..18ef2d2d77
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems-file.c
@@ -0,0 +1,334 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS RFS File Handlers
+ *
+ * This file contains the set of handlers used to process operations on
+ * RFS file nodes.
+ */
+
+#include <rtems/rfs/rtems-rfs-file.h>
+#include "rtems-rfs-rtems.h"
+
+/**
+ * This routine processes the open() system call. Note that there is nothing
+ * special to be done at open() time.
+ *
+ * @param iop
+ * @param pathname
+ * @param flag
+ * @param mode
+ * @return int
+ */
+
+static int
+rtems_rfs_rtems_file_open (rtems_libio_t* iop,
+ const char* pathname,
+ uint32_t flag,
+ uint32_t mode)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (&iop->pathinfo);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_iop_ino (iop);
+ rtems_rfs_file_handle* file;
+ uint32_t flags;
+ int rc;
+
+ flags = 0;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_OPEN))
+ printf("rtems-rfs: file-open: path:%s ino:%ld flags:%04lx mode:%04lx\n",
+ pathname, ino, flags, mode);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_file_open (fs, ino, flags, &file);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("file-open: open", rc);
+ }
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_OPEN))
+ printf("rtems-rfs: file-open: handle:%p\n", file);
+
+ iop->file_info = file;
+
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/**
+ * This routine processes the close() system call. Note that there is nothing
+ * to flush at this point.
+ *
+ * @param iop
+ * @return int
+ */
+static int
+rtems_rfs_rtems_file_close (rtems_libio_t* iop)
+{
+ rtems_rfs_file_handle* file = iop->file_info;
+ rtems_rfs_file_system* fs = rtems_rfs_file_fs (file);
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_CLOSE))
+ printf("rtems-rfs: file-close: handle:%p\n", file);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_file_close (fs, file);
+ if (rc > 0)
+ rc = rtems_rfs_rtems_error ("file-close: file close", rc);
+
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/**
+ * This routine processes the read() system call.
+ *
+ * @param iop
+ * @param buffer
+ * @param count
+ * @return int
+ */
+ssize_t
+rtems_rfs_rtems_file_read (rtems_libio_t* iop,
+ void* buffer,
+ size_t count)
+{
+ rtems_rfs_file_handle* file = iop->file_info;
+ rtems_rfs_pos pos = iop->offset;
+ uint8_t* data = buffer;
+ ssize_t read = 0;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_READ))
+ printf("rtems-rfs: file-read: handle:%p count:%ld\n", file, count);
+
+ rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));
+
+ if (pos < rtems_rfs_file_size (file))
+ {
+ while (count)
+ {
+ size_t size;
+
+ rc = rtems_rfs_file_io_start (file, &size, true);
+ if (rc > 0)
+ {
+ read = rtems_rfs_rtems_error ("file-read: read: io-start", rc);
+ break;
+ }
+
+ if (size == 0)
+ break;
+
+ if (size > count)
+ size = count;
+
+ memcpy (data, rtems_rfs_file_data (file), size);
+
+ data += size;
+ count -= size;
+ read += size;
+
+ rc = rtems_rfs_file_io_end (file, size, true);
+ if (rc > 0)
+ {
+ read = rtems_rfs_rtems_error ("file-read: read: io-end", rc);
+ break;
+ }
+ }
+ }
+
+ rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
+
+ return read;
+}
+
+/**
+ * This routine processes the write() system call.
+ *
+ * @param iop
+ * @param buffer
+ * @param count
+ * @return ssize_t
+ */
+ssize_t
+rtems_rfs_rtems_file_write (rtems_libio_t* iop,
+ const void* buffer,
+ size_t count)
+{
+ rtems_rfs_file_handle* file = iop->file_info;
+ rtems_rfs_pos pos = iop->offset;
+ const uint8_t* data = buffer;
+ ssize_t write = 0;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_WRITE))
+ printf("rtems-rfs: file-write: handle:%p count:%ld\n", file, count);
+
+ rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));
+
+ /*
+ * If the iop position is past the physical end of the file we need to set the
+ * file size to the new length before writing.
+ */
+
+ if (pos > rtems_rfs_file_size (file))
+ {
+ rc = rtems_rfs_file_set_size (file, pos);
+ if (rc)
+ return rtems_rfs_rtems_error ("file-write: write extend", rc);
+ rtems_rfs_file_set_bpos (file, pos);
+ }
+
+ while (count)
+ {
+ size_t size = count;
+
+ rc = rtems_rfs_file_io_start (file, &size, false);
+ if (rc)
+ {
+ write = rtems_rfs_rtems_error ("file-write: write open", rc);
+ break;
+ }
+
+ if (size > count)
+ size = count;
+
+ memcpy (rtems_rfs_file_data (file), data, size);
+
+ data += size;
+ count -= size;
+ write += size;
+
+ rc = rtems_rfs_file_io_end (file, size, false);
+ if (rc)
+ {
+ write = rtems_rfs_rtems_error ("file-write: write close", rc);
+ break;
+ }
+ }
+
+ iop->size = rtems_rfs_file_size (file);
+
+ rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
+
+ return write;
+}
+
+/**
+ * This routine processes the ioctl() system call.
+ *
+ * @note No ioctl()'s are currently supported for RFS files.
+ *
+ * @param iop
+ * @param command
+ * @param buffer
+ */
+
+int
+rtems_rfs_rtems_file_ioctl (rtems_libio_t* iop, uint32_t command, void* buffer)
+{
+ return 0;
+}
+
+/**
+ * This routine processes the lseek() system call.
+ *
+ * @param iop
+ * @param offset
+ * @param whence
+ * @return rtems_off64_t
+ */
+rtems_off64_t
+rtems_rfs_rtems_file_lseek (rtems_libio_t* iop,
+ rtems_off64_t offset,
+ int whence)
+{
+ rtems_rfs_file_handle* file = iop->file_info;
+ rtems_rfs_pos pos;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_LSEEK))
+ printf("rtems-rfs: file-lseek: handle:%p offset:%Ld\n", file, offset);
+
+ pos = iop->offset;
+
+ rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));
+
+ rc = rtems_rfs_file_seek (file, pos, &pos);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
+ return rtems_rfs_rtems_error ("file_lseek: lseek", rc);
+ }
+
+ rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
+
+ return iop->offset;
+}
+
+/**
+ * This routine processes the ftruncate() system call.
+ *
+ * @param iop
+ * @param length
+ * @return int
+ */
+int
+rtems_rfs_rtems_file_ftruncate (rtems_libio_t* iop,
+ rtems_off64_t length)
+{
+ rtems_rfs_file_handle* file = iop->file_info;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FILE_FTRUNC))
+ printf("rtems-rfs: file-ftrunc: handle:%p length:%Ld\n", file, length);
+
+ rtems_rfs_rtems_lock (rtems_rfs_file_fs (file));
+
+ rc = rtems_rfs_file_set_size (file, length);
+ if (rc)
+ rc = rtems_rfs_rtems_error ("file_ftruncate: set size", rc);
+
+ iop->size = rtems_rfs_file_size (file);
+
+ rtems_rfs_rtems_unlock (rtems_rfs_file_fs (file));
+
+ return rc;
+}
+
+/*
+ * Set of operations handlers for operations on RFS files.
+ */
+
+const rtems_filesystem_file_handlers_r rtems_rfs_rtems_file_handlers = {
+ .open_h = rtems_rfs_rtems_file_open,
+ .close_h = rtems_rfs_rtems_file_close,
+ .read_h = rtems_rfs_rtems_file_read,
+ .write_h = rtems_rfs_rtems_file_write,
+ .ioctl_h = rtems_rfs_rtems_file_ioctl,
+ .lseek_h = rtems_rfs_rtems_file_lseek,
+ .fstat_h = rtems_rfs_rtems_stat,
+ .fchmod_h = rtems_rfs_rtems_fchmod,
+ .ftruncate_h = rtems_rfs_rtems_file_ftruncate,
+ .fpathconf_h = NULL,
+ .fsync_h = rtems_rfs_rtems_fdatasync,
+ .fdatasync_h = rtems_rfs_rtems_fdatasync,
+ .fcntl_h = rtems_rfs_rtems_fcntl,
+ .rmnod_h = rtems_rfs_rtems_rmnod
+};
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems-utils.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems-utils.c
new file mode 100644
index 0000000000..f14cbd8af7
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems-utils.c
@@ -0,0 +1,240 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * Set of utility functions to support RTEMS RFS on RTEMS.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+
+#include "rtems-rfs-rtems.h"
+
+bool
+rtems_rfs_rtems_eval_perms (rtems_rfs_inode_handle* inode, int flags)
+{
+ uid_t st_uid;
+ gid_t st_gid;
+ uint16_t uid;
+ uint16_t gid;
+ uint16_t mode;
+ int flags_to_test;
+
+ uid = rtems_rfs_inode_get_uid (inode);
+ gid = rtems_rfs_inode_get_gid (inode);
+ mode = rtems_rfs_inode_get_mode (inode);
+
+#if defined (RTEMS_POSIX_API)
+ st_uid = geteuid ();
+ st_gid = getegid ();
+#else
+ st_uid = uid;
+ st_gid = gid;
+#endif
+
+ /*
+ * Check if I am owner or a group member or someone else.
+ */
+ flags_to_test = flags;
+
+ if ((st_uid == 0) || (st_uid == uid))
+ flags_to_test |= flags << 6;
+ if ((st_uid == 0) || (st_gid == gid))
+ flags_to_test |= flags << 3;
+ else
+ /* must be other - already set above */;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PERMS))
+ printf ("rtems-rfs: eval-perms: uid=%d gid=%d iuid=%d igid=%d " \
+ "flags=%o flags_to_test=%o mode=%o (%o)\n",
+ st_uid, st_gid, uid, gid,
+ flags, flags_to_test, mode & 0777,
+ flags_to_test & (mode & 0777));
+
+ /*
+ * If all of the flags are set we have permission
+ * to do this.
+ */
+ if ((flags_to_test & (mode & 0777)) != 0)
+ return true;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PERMS))
+ printf("rtems-rfs: eval-perms: perms failed\n");
+
+ return false;
+}
+
+/*
+ * The following sets the handlers based on the type of inode.
+ */
+
+bool
+rtems_rfs_rtems_set_handlers (rtems_filesystem_location_info_t* loc,
+ rtems_rfs_inode_handle* inode)
+{
+ uint16_t mode = rtems_rfs_inode_get_mode (inode);
+ loc->handlers = NULL;
+ if (RTEMS_RFS_S_ISDIR (mode))
+ loc->handlers = rtems_rfs_rtems_handlers (dir);
+ else if (RTEMS_RFS_S_ISCHR (mode) || RTEMS_RFS_S_ISBLK(mode))
+ loc->handlers = rtems_rfs_rtems_handlers (device);
+ else if (RTEMS_RFS_S_ISLNK (mode))
+ loc->handlers = rtems_rfs_rtems_handlers (link);
+ else if (RTEMS_RFS_S_ISREG (mode))
+ loc->handlers = rtems_rfs_rtems_handlers (file);
+ else
+ {
+ printf ("rtems-rfs: mode type unknown: %04x\n", mode);
+ return false;
+ }
+ return true;
+}
+
+uint16_t
+rtems_rfs_rtems_imode (mode_t mode)
+{
+ /*
+ * Mapping matches RTEMS so no need to change.
+ */
+ return mode;
+}
+
+mode_t
+rtems_rfs_rtems_mode (int imode)
+{
+ /*
+ * Mapping matches RTEMS so no need to change.
+ */
+ return imode;
+}
+
+/*
+ * Only provide if there is no macro version.
+ */
+#if !defined (rtems_rfs_rtems_error)
+int
+rtems_rfs_rtems_error (const char* mesg, int error)
+{
+ if (error)
+ printf ("rtems-rfs: %s: %d: %s\n", mesg, error, strerror (error));
+ errno = error;
+ return error == 0 ? 0 : -1;
+}
+#endif
+
+#if RTEMS_RFS_RTEMS_TRACE
+static uint32_t rtems_rfs_rtems_trace_mask;
+
+bool
+rtems_rfs_rtems_trace (uint32_t mask)
+{
+ bool result = false;
+ if (mask & rtems_rfs_rtems_trace_mask)
+ result = true;
+ return result;
+}
+
+void
+rtems_rfs_trace_rtems_set_mask (uint32_t mask)
+{
+ rtems_rfs_rtems_trace_mask |= mask;
+}
+
+void
+rtems_rfs_trace_rtems_clear_mask (uint32_t mask)
+{
+ rtems_rfs_rtems_trace_mask &= ~mask;
+}
+
+int
+rtems_rfs_rtems_trace_shell_command (int argc, char *argv[])
+{
+ const char* table[] =
+ {
+ "error-msgs",
+ "eval-path"
+ "eval-for-make",
+ "eval-perms",
+ "mknod",
+ "rmnod",
+ "link",
+ "unlink",
+ "chown",
+ "readlink",
+ "fchmod",
+ "stat",
+ "dir-rmnod",
+ "file-open",
+ "file-close",
+ "file-read",
+ "file-write",
+ "file-lseek",
+ "file-ftrunc"
+ };
+
+ bool set = true;
+ int arg;
+ int t;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ switch (argv[arg][1])
+ {
+ case 'h':
+ printf ("usage: %s [-hl] [set/clear] [flags]\n", argv[0]);
+ return 0;
+ case 'l':
+ printf ("%s: valid flags to set or clear are:\n", argv[0]);
+ for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++)
+ printf (" %s\n", table[t]);
+ return 0;
+ default:
+ printf ("error: unknown option\n");
+ return 1;
+ }
+ }
+ else
+ {
+ uint32_t value = 0;
+ if (strcmp (argv[arg], "set") == 0)
+ set = true;
+ if (strcmp (argv[arg], "clear") == 0)
+ set = false;
+ else if (strcmp (argv[arg], "all") == 0)
+ value = RTEMS_RFS_RTEMS_DEBUG_ALL;
+ else
+ {
+ for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++)
+ {
+ if (strcmp (argv[arg], table[t]) == 0)
+ {
+ value = 1 << t;
+ break;
+ }
+ }
+ }
+
+ if (set)
+ rtems_rfs_rtems_trace_mask |= value;
+ else
+ rtems_rfs_rtems_trace_mask &= ~value;
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems.c b/cpukit/libfs/src/rfs/rtems-rfs-rtems.c
new file mode 100644
index 0000000000..60f3fdf429
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems.c
@@ -0,0 +1,1235 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System Interface for RTEMS.
+ */
+
+#include <stdlib.h>
+
+#include <rtems/rfs/rtems-rfs-file.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+#include <rtems/rfs/rtems-rfs-link.h>
+#include "rtems-rfs-rtems.h"
+
+/**
+ * The libio permissions for read/execute.
+ */
+#define RTEMS_LIBIO_PERMS_RX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_READ)
+/**
+ * The libio permissions for write/execute.
+ */
+#define RTEMS_LIBIO_PERMS_WX (RTEMS_LIBIO_PERMS_SEARCH | RTEMS_LIBIO_PERMS_WRITE)
+
+/**
+ * Evaluate the path to a node that wishes to be accessed. The pathloc is
+ * returned with the ino to the node to be accessed.
+ *
+ * The routine starts from the root stripping away any leading path separators
+ * breaking the path up into the node names and checking an inode exists for
+ * that node name. Permissions are checked to insure access to the node is
+ * allowed. A path to a node must be accessable all the way even if the end
+ * result is directly accessable. As a user on Linux try "ls /root/../tmp" and
+ * you will see if fails.
+ *
+ * The whole process is complicated by crossmount paths where we head down into
+ * this file system only to return to the top and out to a another mounted file
+ * system. For example we are mounted on '/e' and the user enters "ls
+ * /e/a/b/../../dev". We need to head down then back up.
+ *
+ * @param path
+ * @param pathlen
+ * @param flags
+ * @param pathloc
+ */
+int
+rtems_rfs_rtems_eval_path (const char* path,
+ int pathlen,
+ int flags,
+ rtems_filesystem_location_info_t* pathloc)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_inode_handle inode;
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ uint32_t doff = 0;
+ const char* node;
+ int node_len;
+ int stripped;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
+ printf ("rtems-rfs-rtems: eval-path: in: path:%s pathlen:%i ino:%ld\n",
+ path, pathlen, ino);
+
+ /*
+ * Eat any separators at the start of the path.
+ */
+ stripped = rtems_filesystem_prefix_separators (path, pathlen);
+ path += stripped;
+ pathlen -= stripped;
+
+ rtems_rfs_rtems_lock (fs);
+
+ while (true)
+ {
+ /*
+ * Open and load the inode.
+ */
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_path: opening inode", rc);
+ }
+
+ /*
+ * Is this the end of the pathname we where given ?
+ */
+ if ((*path == '\0') || (pathlen == 0))
+ break;
+
+ /*
+ * If a directory the execute bit must be set for us to enter.
+ */
+ if (RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)) &&
+ !rtems_rfs_rtems_eval_perms (&inode, RTEMS_LIBIO_PERMS_SEARCH))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_path: eval perms", EACCES);
+ }
+
+ /*
+ * Extract the node name we will look for this time around.
+ */
+ node = path;
+ node_len = 0;
+ while (!rtems_filesystem_is_separator (*path) &&
+ (*path != '\0') && pathlen &&
+ (node_len < (rtems_rfs_fs_max_name (fs) - 1)))
+ {
+ path++;
+ pathlen--;
+ node_len++;
+ }
+
+ /*
+ * Eat any separators at start of the path.
+ */
+ stripped = rtems_filesystem_prefix_separators (path, pathlen);
+ path += stripped;
+ pathlen -= stripped;
+ node_len += stripped;
+
+ /*
+ * If the node is the current directory and there is more path to come move
+ * on it else we are at the inode we want.
+ */
+ if (rtems_rfs_current_dir (node))
+ {
+ if (*path)
+ continue;
+ break;
+ }
+
+ /*
+ * If the node is a parent we must move up one directory. If the location
+ * is on another file system we have a crossmount so we call that file
+ * system to handle the remainder of the path.
+ */
+ if (rtems_rfs_parent_dir (node))
+ {
+ /*
+ * If we are at root inode of the file system we have a crossmount path.
+ */
+ if (ino == RTEMS_RFS_ROOT_INO)
+ {
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
+ printf("rtems-rfs-rtems: eval-path: crossmount: path:%s (%d)\n",
+ path - node_len, pathlen + node_len);
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ *pathloc = pathloc->mt_entry->mt_point_node;
+ return (*pathloc->ops->evalpath_h)(path - node_len, pathlen + node_len,
+ flags, pathloc);
+ }
+
+ /*
+ * We need to find the parent of this node.
+ */
+ rc = rtems_rfs_dir_lookup_ino (fs, &inode, "..", 2, &ino, &doff);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_path: read parent inode", rc);
+ }
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
+ printf("rtems-rfs-rtems: eval-path: parent: ino:%ld\n", ino);
+ }
+ else
+ {
+ /*
+ * Look up the node name in this directory. If found drop through, close
+ * the current inode and let the loop open the inode so the mode can be
+ * read and handlers set.
+ */
+ rc = rtems_rfs_dir_lookup_ino (fs, &inode,
+ node, node_len - stripped, &ino, &doff);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return ((errno = rc) == 0) ? 0 : -1;
+ }
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
+ printf("rtems-rfs-rtems: eval-path: down: path:%s ino:%ld\n", node, ino);
+ }
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_path: closing node", rc);
+ }
+ }
+
+ rtems_rfs_rtems_set_pathloc_ino (pathloc, ino);
+ rtems_rfs_rtems_set_pathloc_doff (pathloc, doff);
+
+ rc = rtems_rfs_rtems_set_handlers (pathloc, &inode) ? 0 : EIO;
+
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH))
+ printf("rtems-rfs-rtems: eval-path: ino:%ld\n", ino);
+
+ return rc;
+}
+
+/**
+ * The following routine evaluates a path for a new node to be created. The
+ * pathloc is returned with a pointer to the parent of the new node. The name
+ * is returned with a pointer to the first character in the new node name. The
+ * parent node is verified to be a directory.
+ *
+ * @param path
+ * @param pathloc
+ * @param name
+ * @return int
+ */
+int
+rtems_rfs_rtems_eval_for_make (const char* path,
+ rtems_filesystem_location_info_t* pathloc,
+ const char** name)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_inode_handle inode;
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_rfs_ino node_ino;
+ uint32_t doff = 0;
+ const char* node;
+ int node_len;
+ int stripped;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
+ printf ("rtems-rfs-rtems: eval-for-make: path:%s ino:%ld\n", path, ino);
+
+ *name = path + strlen (path);
+
+ while (*name != path)
+ {
+ (*name)--;
+ if (rtems_filesystem_is_separator (**name))
+ {
+ (*name)++;
+ break;
+ }
+ }
+
+ /*
+ * Eat any separators at start of the path.
+ */
+ stripped = rtems_filesystem_prefix_separators (path, strlen(path));
+ path += stripped;
+
+ rtems_rfs_rtems_lock (fs);
+
+ while (true)
+ {
+ /*
+ * Open and load the inode.
+ */
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: read ino", rc);
+ }
+
+ /*
+ * If a directory the execute bit must be set for us to enter.
+ */
+ if (RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)) &&
+ !rtems_rfs_rtems_eval_perms (&inode, RTEMS_LIBIO_PERMS_SEARCH))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: eval perms", EACCES);
+ }
+
+ /*
+ * Is this the end of the pathname we where given ?
+ */
+ if (path == *name)
+ break;
+
+ /*
+ * Extract the node name we will look for this time around.
+ */
+ node = path;
+ node_len = 0;
+ while (!rtems_filesystem_is_separator(*path) &&
+ (*path != '\0') &&
+ (node_len < (rtems_rfs_fs_max_name (fs) - 1)))
+ {
+ node_len++;
+ path++;
+ }
+
+ /*
+ * Eat any separators at start of the new path.
+ */
+ stripped = rtems_filesystem_prefix_separators (path, strlen (path));
+ path += stripped;
+ node_len += stripped;
+
+ /*
+ * If the node is the current directory and there is more path to come move
+ * on it else we are at the inode we want.
+ */
+ if (rtems_rfs_current_dir (node))
+ {
+ if (*path)
+ continue;
+ break;
+ }
+
+ /*
+ * If the node is a parent we must move up one directory. If the location
+ * is on another file system we have a crossmount so we call that file
+ * system to handle the remainder of the path.
+ */
+ if (rtems_rfs_parent_dir (path))
+ {
+ /*
+ * If we are at the root inode of the file system we have a crossmount
+ * path.
+ */
+ if (ino == RTEMS_RFS_ROOT_INO)
+ {
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
+ printf("rtems-rfs-rtems: eval-for-make: crossmount: path:%s\n",
+ path - node_len);
+
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ *pathloc = pathloc->mt_entry->mt_point_node;
+ return (*pathloc->ops->evalformake_h)(path - node_len, pathloc, name);
+ }
+
+ /*
+ * If not a directory give and up return. We cannot change dir from a
+ * regular file or device node.
+ */
+ if (!RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: not dir", ENOTSUP);
+ }
+
+ /*
+ * We need to find the parent of this node.
+ */
+ rc = rtems_rfs_dir_lookup_ino (fs, &inode, "..", 2, &ino, &doff);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: read parent inode", rc);
+ }
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
+ printf ("rtems-rfs-rtems: eval-for-make: parent: ino:%ld\n", ino);
+ }
+ else
+ {
+ /*
+ * Read the inode so we know it exists and what type it is.
+ */
+ rc = rtems_rfs_dir_lookup_ino (fs, &inode,
+ node, node_len - stripped, &ino, &doff);
+ if (rc > 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: reading inode", rc);
+ }
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
+ printf("rtems-rfs-rtems: eval-for-make: down: path:%s ino:%ld\n",
+ node, ino);
+ }
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: closing node", rc);
+ }
+ }
+
+ if (!RTEMS_RFS_S_ISDIR (rtems_rfs_inode_get_mode (&inode)))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: not dir", ENOTDIR);
+ }
+
+ if (!rtems_rfs_rtems_eval_perms (&inode, RTEMS_LIBIO_PERMS_WX))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: cannot write", EACCES);
+ }
+
+ /*
+ * Make sure the name does not already exists in the directory.
+ */
+ rc = rtems_rfs_dir_lookup_ino (fs, &inode, *name, strlen (*name),
+ &node_ino, &doff);
+ if (rc == 0)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: found name", EEXIST);
+ }
+
+ if (rc != ENOENT)
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("eval_for_make: look up", rc);
+ }
+
+ /*
+ * Set the parent ino in the path location.
+ */
+
+ rtems_rfs_rtems_set_pathloc_ino (pathloc, ino);
+ rtems_rfs_rtems_set_pathloc_doff (pathloc, doff);
+
+ rc = rtems_rfs_rtems_set_handlers (pathloc, &inode) ? 0 : EIO;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE))
+ printf("rtems-rfs-rtems: eval-for-make: parent ino:%ld name:%s\n",
+ ino, *name);
+
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+
+ return rc;
+}
+
+/**
+ * The following rouine creates a new link node under parent with the name
+ * given in name. The link node is set to point to the node at to_loc.
+ *
+ * @param to_loc
+ * @param parent_loc
+ * @param name
+ * @return int
+ */
+int
+rtems_rfs_rtems_link (rtems_filesystem_location_info_t* to_loc,
+ rtems_filesystem_location_info_t* parent_loc,
+ const char* name)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (to_loc);
+ rtems_rfs_ino target = rtems_rfs_rtems_get_pathloc_ino (to_loc);
+ rtems_rfs_ino parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_LINK))
+ printf ("rtems-rfs-rtems: link: in: parent:%ld target:%ld\n",
+ parent, target);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_link (fs, name, strlen (name), parent, target);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("link: linking", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * Routine to remove a link node from the file system.
+ *
+ * @param parent_loc
+ * @param loc
+ * @return int
+ */
+
+int
+rtems_rfs_rtems_unlink (rtems_filesystem_location_info_t* parent_loc,
+ rtems_filesystem_location_info_t* loc)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (parent_loc);
+ rtems_rfs_ino parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (loc);
+ uint32_t doff = rtems_rfs_rtems_get_pathloc_doff (loc);
+ int rc;
+
+ rtems_rfs_rtems_lock (fs);
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_UNLINK))
+ printf("rtems-rfs-rtems: unlink: parent:%ld doff:%lu ino:%ld\n",
+ parent, doff, ino);
+
+ rc = rtems_rfs_unlink (fs, parent, ino, doff, false);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("unlink: unlink inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * The following verifies that and returns the type of node that the loc refers
+ * to.
+ *
+ * @param pathloc
+ * @return rtems_filesystem_node_types_t
+ */
+
+rtems_filesystem_node_types_t
+rtems_rfs_rtems_node_type (rtems_filesystem_location_info_t* pathloc)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_filesystem_node_types_t type;
+ rtems_rfs_inode_handle inode;
+ uint16_t mode;
+ int rc;
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("node_type: opening inode", rc);
+ }
+
+ /*
+ * Do not return RTEMS_FILESYSTEM_HARD_LINK because this would result in an
+ * eval link which does not make sense in the case of the RFS file
+ * system. All directory entries are links to an inode. A link such as a HARD
+ * link is actually the normal path to a regular file, directory, device
+ * etc's inode. Links to inodes can be considered "the real" one, yet they
+ * are all links.
+ */
+ mode = rtems_rfs_inode_get_mode (&inode);
+ if (RTEMS_RFS_S_ISDIR (mode))
+ type = RTEMS_FILESYSTEM_DIRECTORY;
+ else if (RTEMS_RFS_S_ISLNK (mode))
+ type = RTEMS_FILESYSTEM_SYM_LINK;
+ else if (RTEMS_RFS_S_ISBLK (mode) || RTEMS_RFS_S_ISCHR (mode))
+ type = RTEMS_FILESYSTEM_DEVICE;
+ else
+ type = RTEMS_FILESYSTEM_MEMORY_FILE;
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("node_type: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return type;
+}
+
+/**
+ * This routine is the implementation of the chown() system call for the
+ * RFS.
+ *
+ * @param pathloc
+ * @param owner
+ * @param group
+ * return int
+ */
+
+static int
+rtems_rfs_rtems_chown (rtems_filesystem_location_info_t *pathloc,
+ uid_t owner,
+ gid_t group)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_rfs_inode_handle inode;
+#if defined (RTEMS_POSIX_API)
+ uid_t uid;
+#endif
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_CHOWN))
+ printf ("rtems-rfs-rtems: chown: in: ino:%ld uid:%d gid:%d\n",
+ ino, owner, group);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("chown: opening inode", rc);
+ }
+
+ /*
+ * Verify I am the owner of the node or the super user.
+ */
+
+#if defined (RTEMS_POSIX_API)
+ uid = geteuid();
+
+ if ((uid != rtems_rfs_inode_get_uid (&inode)) && (uid != 0))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("chown: not able", EPERM);
+ }
+#endif
+
+ rtems_rfs_inode_set_uid_gid (&inode, owner, group);
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("chown: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * This routine is the RFS free node handler for the file system operations
+ * table. The RFS does not need to free anything.
+ *
+ * @param pathloc
+ * @retval 0 Always returned.
+ */
+
+int
+rtems_rfs_rtems_freenodinfo (rtems_filesystem_location_info_t* pathloc)
+{
+ return 0;
+}
+
+/**
+ * This routine is the implementation of the utime() system call for the
+ * RFS.
+ *
+ * @param pathloc
+ * @param atime
+ * @param mtime
+ * return int
+ */
+
+int
+rtems_rfs_rtems_utime(rtems_filesystem_location_info_t* pathloc,
+ time_t atime,
+ time_t mtime)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_rfs_inode_handle inode;
+ int rc;
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("utime: read inode", rc);
+ }
+
+ rtems_rfs_inode_set_atime (&inode, atime);
+ rtems_rfs_inode_set_mtime (&inode, mtime);
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("utime: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * The following rouine creates a new symbolic link node under parent with the
+ * name given in name. The node is set to point to the node at to_loc.
+ *
+ * @param parent_loc
+ * @param link_name
+ * @param node_name
+ * return int
+ */
+
+int
+rtems_rfs_rtems_symlink (rtems_filesystem_location_info_t* parent_loc,
+ const char* link_name,
+ const char* node_name)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (parent_loc);
+ rtems_rfs_ino parent = rtems_rfs_rtems_get_pathloc_ino (parent_loc);
+ uid_t uid;
+ gid_t gid;
+ int rc;
+
+#if defined(RTEMS_POSIX_API)
+ uid = geteuid ();
+ gid = getegid ();
+#else
+ uid = 0;
+ gid = 0;
+#endif
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_symlink (fs, node_name, strlen (node_name),
+ link_name, strlen (link_name),
+ uid, gid, parent);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("symlink: linking", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * The following rouine puts the symblic links destination name into buf.
+ *
+ * @param loc
+ * @param buf
+ * @param bufsize
+ * @return int
+ */
+
+int
+rtems_rfs_rtems_readlink (rtems_filesystem_location_info_t* pathloc,
+ char* buf,
+ size_t bufsize)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ size_t length;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_READLINK))
+ printf ("rtems-rfs-rtems: readlink: in: ino:%ld\n", ino);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_symlink_read (fs, ino, buf, bufsize, &length);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("readlink: reading link", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return (int) length;
+}
+
+/**
+ * File change mode routine.
+ *
+ * @param pathloc
+ * @param mode
+ * @return int
+ */
+int
+rtems_rfs_rtems_fchmod (rtems_filesystem_location_info_t* pathloc,
+ mode_t mode)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_rfs_inode_handle inode;
+ uint16_t imode;
+#if defined (RTEMS_POSIX_API)
+ uid_t uid;
+#endif
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_FCHMOD))
+ printf ("rtems-rfs-rtems: fchmod: in: ino:%ld mode:%06o\n",
+ ino, mode);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("fchmod: opening inode", rc);
+ }
+
+ imode = rtems_rfs_inode_get_mode (&inode);
+
+ /*
+ * Verify I am the owner of the node or the super user.
+ */
+#if defined (RTEMS_POSIX_API)
+ uid = geteuid();
+
+ if ((uid != rtems_rfs_inode_get_uid (&inode)) && (uid != 0))
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("fchmod: not owner", EPERM);
+ }
+#endif
+
+ imode &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
+ imode |= mode & (S_IRWXU | S_IRWXG | S_IRWXO | S_ISUID | S_ISGID | S_ISVTX);
+
+ rtems_rfs_inode_set_mode (&inode, imode);
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("fchmod: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * The following routine does a fcntl on an node.
+ *
+ * @param cmd
+ * @param iop
+ * @return int
+ */
+
+int
+rtems_rfs_rtems_fcntl (int cmd,
+ rtems_libio_t* iop)
+{
+ return 0;
+}
+
+/**
+ * The following routine does a stat on a node.
+ *
+ * @param pathloc
+ * @param buf
+ * @return int
+ */
+
+int
+rtems_rfs_rtems_stat (rtems_filesystem_location_info_t* pathloc,
+ struct stat* buf)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_rfs_inode_handle inode;
+ rtems_rfs_file_shared* shared;
+ uint16_t mode;
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_STAT))
+ printf ("rtems-rfs-rtems: stat: in: ino:%ld\n", ino);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("stat: opening inode", rc);
+ }
+
+ mode = rtems_rfs_inode_get_mode (&inode);
+
+ if (RTEMS_RFS_S_ISCHR (mode) || RTEMS_RFS_S_ISBLK (mode))
+ {
+ buf->st_rdev =
+ rtems_filesystem_make_dev_t (rtems_rfs_inode_get_block (&inode, 0),
+ rtems_rfs_inode_get_block (&inode, 1));
+ }
+
+ buf->st_dev = rtems_rfs_fs_device (fs);
+ buf->st_ino = ino;
+ buf->st_mode = rtems_rfs_rtems_mode (mode);
+ buf->st_nlink = rtems_rfs_inode_get_links (&inode);
+ buf->st_uid = rtems_rfs_inode_get_uid (&inode);
+ buf->st_gid = rtems_rfs_inode_get_gid (&inode);
+
+ /*
+ * Need to check is the ino is an open file. If so we take the values from
+ * the open file rather than the inode.
+ */
+ shared = rtems_rfs_file_get_shared (fs, ino);
+
+ if (shared)
+ {
+ buf->st_atime = rtems_rfs_file_shared_get_atime (shared);
+ buf->st_mtime = rtems_rfs_file_shared_get_mtime (shared);
+ buf->st_ctime = rtems_rfs_file_shared_get_ctime (shared);
+ buf->st_blocks = rtems_rfs_file_shared_get_block_count (shared);
+
+ if (S_ISLNK (buf->st_mode))
+ buf->st_size = rtems_rfs_file_shared_get_block_offset (shared);
+ else
+ buf->st_size = rtems_rfs_file_shared_get_size (fs, shared);
+ }
+ else
+ {
+ buf->st_atime = rtems_rfs_inode_get_atime (&inode);
+ buf->st_mtime = rtems_rfs_inode_get_mtime (&inode);
+ buf->st_ctime = rtems_rfs_inode_get_ctime (&inode);
+ buf->st_blocks = rtems_rfs_inode_get_block_count (&inode);
+
+ if (S_ISLNK (buf->st_mode))
+ buf->st_size = rtems_rfs_inode_get_block_offset (&inode);
+ else
+ buf->st_size = rtems_rfs_inode_get_size (fs, &inode);
+ }
+
+ buf->st_blksize = rtems_rfs_fs_block_size (fs);
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("stat: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/**
+ * Routine to create a node in the RFS file system.
+ *
+ * @param name
+ * @param mode
+ * @param dev
+ * @param pathloc
+ * @return int
+ */
+
+int
+rtems_rfs_rtems_mknod (const char *name,
+ mode_t mode,
+ dev_t dev,
+ rtems_filesystem_location_info_t *pathloc)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino parent = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ rtems_rfs_ino ino;
+ rtems_rfs_inode_handle inode;
+ uid_t uid;
+ gid_t gid;
+ int rc;
+
+#if defined(RTEMS_POSIX_API)
+ uid = geteuid ();
+ gid = getegid ();
+#else
+ uid = 0;
+ gid = 0;
+#endif
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_inode_create (fs, parent, name, strlen (name),
+ rtems_rfs_rtems_imode (mode),
+ 1, uid, gid, &ino);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("mknod: inode create", rc);
+ }
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("mknod: inode open", rc);
+ }
+
+ if (S_ISDIR(mode) || S_ISREG(mode))
+ {
+ }
+ else if (S_ISCHR (mode) || S_ISBLK (mode))
+ {
+ int major;
+ int minor;
+ rtems_filesystem_split_dev_t (dev, major, minor);
+ rtems_rfs_inode_set_block (&inode, 0, major);
+ rtems_rfs_inode_set_block (&inode, 1, minor);
+ }
+ else
+ {
+ rtems_rfs_inode_close (fs, &inode);
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("mknod: bad mode", EINVAL);
+ }
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("mknod: closing inode", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/**
+ * Routine to remove a node from the RFS file system.
+ *
+ * @param parent_pathloc
+ * @param pathloc
+ */
+int
+rtems_rfs_rtems_rmnod (rtems_filesystem_location_info_t* parent_pathloc,
+ rtems_filesystem_location_info_t* pathloc)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+ rtems_rfs_ino parent = rtems_rfs_rtems_get_pathloc_ino (parent_pathloc);
+ rtems_rfs_ino ino = rtems_rfs_rtems_get_pathloc_ino (pathloc);
+ uint32_t doff = rtems_rfs_rtems_get_pathloc_doff (pathloc);
+ int rc;
+
+ if (rtems_rfs_rtems_trace (RTEMS_RFS_RTEMS_DEBUG_RMNOD))
+ printf ("rtems-rfs: rmnod: parent:%ld doff:%lu, ino:%ld\n",
+ parent, doff, ino);
+
+ rtems_rfs_rtems_lock (fs);
+
+ rc = rtems_rfs_unlink (fs, parent, ino, doff, false);
+ if (rc)
+ {
+ rtems_rfs_rtems_unlock (fs);
+ return rtems_rfs_rtems_error ("rmnod: unlinking", rc);
+ }
+
+ rtems_rfs_rtems_unlock (fs);
+ return 0;
+}
+
+/**
+ * The following routine does a sync on an inode node. Currently it flushes
+ * everything related to this device.
+ *
+ * @param iop
+ */
+int
+rtems_rfs_rtems_fdatasync (rtems_libio_t* iop)
+{
+ int rc;
+
+ rc = rtems_rfs_buffer_sync (rtems_rfs_rtems_pathloc_dev (&iop->pathinfo));
+ if (rc)
+ return rtems_rfs_rtems_error ("fdatasync: sync", rc);
+
+ return 0;
+}
+
+/**
+ * Return the file system stat data.
+ *
+ * @param pathloc
+ * @param sb
+ * @return int
+ */
+int
+rtems_rfs_rtems_statvfs (rtems_filesystem_location_info_t* pathloc,
+ struct statvfs* sb)
+{
+ rtems_rfs_file_system* fs = rtems_rfs_rtems_pathloc_dev (pathloc);
+
+ sb->f_bsize = rtems_rfs_fs_block_size (fs);
+ sb->f_frsize = rtems_rfs_fs_media_block_size (fs);
+ sb->f_blocks = rtems_rfs_fs_media_blocks (fs);
+
+ sb->f_fsid = RTEMS_RFS_SB_MAGIC;
+ sb->f_namemax = rtems_rfs_fs_max_name (fs);
+
+ return 0;
+}
+
+/**
+ * Handler table for RFS link nodes
+ */
+const rtems_filesystem_file_handlers_r rtems_rfs_rtems_link_handlers =
+{
+ .open_h = NULL,
+ .close_h = NULL,
+ .read_h = NULL,
+ .write_h = NULL,
+ .ioctl_h = NULL,
+ .lseek_h = NULL,
+ .fstat_h = rtems_rfs_rtems_stat,
+ .fchmod_h = NULL,
+ .ftruncate_h = NULL,
+ .fpathconf_h = NULL,
+ .fsync_h = NULL,
+ .fdatasync_h = NULL,
+ .fcntl_h = NULL,
+ .rmnod_h = rtems_rfs_rtems_rmnod
+};
+
+/**
+ * Forward decl for the ops table.
+ */
+
+int rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t *mt_entry);
+int rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t *mt_entry);
+
+/**
+ * RFS file system operations table
+ */
+const rtems_filesystem_operations_table rtems_rfs_ops =
+{
+ .evalpath_h = rtems_rfs_rtems_eval_path,
+ .evalformake_h = rtems_rfs_rtems_eval_for_make,
+ .link_h = rtems_rfs_rtems_link,
+ .unlink_h = rtems_rfs_rtems_unlink,
+ .node_type_h = rtems_rfs_rtems_node_type,
+ .mknod_h = rtems_rfs_rtems_mknod,
+ .chown_h = rtems_rfs_rtems_chown,
+ .freenod_h = rtems_rfs_rtems_freenodinfo,
+ .mount_h = NULL,
+ .fsmount_me_h = rtems_rfs_rtems_initialise,
+ .unmount_h = NULL,
+ .fsunmount_me_h = rtems_rfs_rtems_shutdown,
+ .utime_h = rtems_rfs_rtems_utime,
+ .eval_link_h = NULL, /* never called cause we lie in the node type */
+ .symlink_h = rtems_rfs_rtems_symlink,
+ .readlink_h = rtems_rfs_rtems_readlink,
+ .statvfs_h = rtems_rfs_rtems_statvfs
+};
+
+/**
+ * Open the file system.
+ */
+
+int
+rtems_rfs_rtems_initialise (rtems_filesystem_mount_table_entry_t* mt_entry)
+{
+ rtems_rfs_rtems_private* rtems;
+ rtems_rfs_file_system* fs;
+ int rc;
+
+ rtems = malloc (sizeof (rtems_rfs_rtems_private));
+ if (!rtems)
+ return rtems_rfs_rtems_error ("initialise: local data", ENOMEM);
+
+ memset (rtems, 0, sizeof (rtems_rfs_rtems_private));
+
+ rc = rtems_rfs_mutex_create (&rtems->access);
+ if (rc > 0)
+ {
+ free (rtems);
+ return rtems_rfs_rtems_error ("initialise: cannot create mutex", rc);
+ }
+
+ rc = rtems_rfs_mutex_lock (&rtems->access);
+ if (rc > 0)
+ {
+ rtems_rfs_mutex_destroy (&rtems->access);
+ free (rtems);
+ return rtems_rfs_rtems_error ("initialise: cannot lock access mutex", rc);
+ }
+
+ rc = rtems_rfs_fs_open (mt_entry->dev, rtems, 0, &fs);
+ if (rc)
+ {
+ free (rtems);
+ return rtems_rfs_rtems_error ("initialise: open", rc);
+ }
+
+ mt_entry->fs_info = fs;
+
+ mt_entry->mt_fs_root.node_access = (void*) RTEMS_RFS_ROOT_INO;
+ mt_entry->mt_fs_root.handlers = &rtems_rfs_rtems_dir_handlers;
+ mt_entry->mt_fs_root.ops = &rtems_rfs_ops;
+
+ rtems_rfs_rtems_unlock (fs);
+
+ return 0;
+}
+
+/**
+ * Shutdown the file system.
+ */
+int
+rtems_rfs_rtems_shutdown (rtems_filesystem_mount_table_entry_t* mt_entry)
+{
+ rtems_rfs_file_system* fs = mt_entry->fs_info;
+ rtems_rfs_rtems_private* rtems;
+ int rc;
+
+ rtems = rtems_rfs_fs_user (fs);
+
+ rc = rtems_rfs_fs_close(fs);
+
+ rtems_rfs_mutex_destroy (&rtems->access);
+ free (rtems);
+
+ return rtems_rfs_rtems_error ("shutdown: close", rc);
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-rtems.h b/cpukit/libfs/src/rfs/rtems-rfs-rtems.h
new file mode 100644
index 0000000000..2c294aaebd
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-rtems.h
@@ -0,0 +1,318 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System RTEMS Header file.
+ *
+ * This file is not to be installed. It binds the RFS file system to RTEMS.
+ */
+
+#if !defined(RTEMS_RFS_RTEMS_DEFINED)
+#define RTEMS_RFS_RTEMS_DEFINED
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <errno.h>
+
+/**
+ * RTEMS RFS RTEMS Error Enable. Set to 1 to printing of errors. Default is off.
+ */
+#define RTEMS_RFS_RTEMS_ERROR 0
+
+/**
+ * RTEMS RFS RTEMS Trace Enable. Set to 1 to printing of errors. Default is off.
+ */
+#define RTEMS_RFS_RTEMS_TRACE 0
+
+/**
+ * If we are not handling errors provide a define that removes the strings from
+ * the code.
+ */
+#if !RTEMS_RFS_RTEMS_ERROR
+#define rtems_rfs_rtems_error(_m, _e) \
+ (((errno = (_e)) == 0) ? 0 : -1)
+#else
+/**
+ * Take the result code and set errno with it and if non-zero return -1 else
+ * return 0.
+ *
+ * @param what The message to print is the error is not zero.
+ * @param error The error code.
+ * @retval -1 An error has occured.
+ * @retval 0 No error.
+ */
+int rtems_rfs_rtems_error (const char* mesg, int error);
+#endif
+
+/**
+ * Trace message defines the RTEMS bindings of the RTEMS RFS. This is a
+ * development tool where can edit the values below to control the various trace
+ * output.
+ */
+#define RTEMS_RFS_RTEMS_DEBUG_ALL (0xffffffff)
+#define RTEMS_RFS_RTEMS_DEBUG_ERROR_MSGS (1 << 0)
+#define RTEMS_RFS_RTEMS_DEBUG_EVAL_PATH (1 << 1)
+#define RTEMS_RFS_RTEMS_DEBUG_EVAL_FOR_MAKE (1 << 2)
+#define RTEMS_RFS_RTEMS_DEBUG_EVAL_PERMS (1 << 3)
+#define RTEMS_RFS_RTEMS_DEBUG_MKNOD (1 << 4)
+#define RTEMS_RFS_RTEMS_DEBUG_RMNOD (1 << 5)
+#define RTEMS_RFS_RTEMS_DEBUG_LINK (1 << 6)
+#define RTEMS_RFS_RTEMS_DEBUG_UNLINK (1 << 7)
+#define RTEMS_RFS_RTEMS_DEBUG_CHOWN (1 << 8)
+#define RTEMS_RFS_RTEMS_DEBUG_READLINK (1 << 9)
+#define RTEMS_RFS_RTEMS_DEBUG_FCHMOD (1 << 10)
+#define RTEMS_RFS_RTEMS_DEBUG_STAT (1 << 11)
+#define RTEMS_RFS_RTEMS_DEBUG_DIR_RMNOD (1 << 12)
+#define RTEMS_RFS_RTEMS_DEBUG_FILE_OPEN (1 << 13)
+#define RTEMS_RFS_RTEMS_DEBUG_FILE_CLOSE (1 << 14)
+#define RTEMS_RFS_RTEMS_DEBUG_FILE_READ (1 << 15)
+#define RTEMS_RFS_RTEMS_DEBUG_FILE_WRITE (1 << 16)
+#define RTEMS_RFS_RTEMS_DEBUG_FILE_LSEEK (1 << 17)
+#define RTEMS_RFS_RTEMS_DEBUG_FILE_FTRUNC (1 << 18)
+
+/**
+ * Call to check if this part is bring traced. If RTEMS_RFS_RTEMS_TRACE is
+ * defined to 0 the code is dead code elminiated when built with -Os, -O2, or
+ * higher.
+ *
+ * @param mask The part of the API to trace.
+ * @retval true Tracing is active for the mask.
+ * @retval false Do not trace.
+ */
+#if RTEMS_RFS_RTEMS_TRACE
+bool rtems_rfs_rtems_trace (uint32_t mask);
+#else
+#define rtems_rfs_rtems_trace(_m) (0)
+#endif
+
+/**
+ * Set the mask.
+ *
+ * @param mask The mask bits to set.
+ * @return The previous mask.
+ */
+#if RTEMS_RFS_RTEMS_TRACE
+void rtems_rfs_rtems_trace_set_mask (uint32_t mask);
+#else
+#define rtems_rfs_rtems_trace_set_mask(_m)
+#endif
+
+/**
+ * Clear the mask.
+ *
+ * @param mask The mask bits to clear.
+ * @return The previous mask.
+ */
+#if RTEMS_RFS_RTEMS_TRACE
+void rtems_rfs_rtems_trace_clear_mask (uint32_t mask);
+#else
+#define rtems_rfs_rtems_trace_clear_mask(_m)
+#endif
+
+/**
+ * Add shell trace shell command.
+ */
+#if RTEMS_RFS_RTEMS_TRACE
+int rtems_rfs_rtems_trace_shell_command (int argc, char *argv[]);
+#endif
+
+#include <rtems/rfs/rtems-rfs-file-system.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+#include <rtems/rfs/rtems-rfs-mutex.h>
+#include <rtems/libio_.h>
+#include <rtems/fs.h>
+
+/**
+ * Private RFS RTEMS Port data.
+ */
+typedef struct rtems_rfs_rtems_private
+{
+ /**
+ * The access lock.
+ */
+ rtems_rfs_mutex access;
+} rtems_rfs_rtems_private;
+/**
+ * Return the file system structure given a path location.
+ *
+ * @param _loc Pointer to the path location.
+ * @return rtems_rfs_file_system*
+ */
+#define rtems_rfs_rtems_pathloc_dev(_loc) \
+ ((rtems_rfs_file_system*)((_loc)->mt_entry->fs_info))
+
+/**
+ * Set the inode number (ino) into the path location.
+ *
+ * @param _loc Pointer to the path location.
+ * @param _ino The ino to set in the path location.
+ */
+#define rtems_rfs_rtems_set_pathloc_ino(_loc, _ino) \
+ (_loc)->node_access = (void*)(_ino)
+
+/**
+ * Get the inode number (ino) given a path location.
+ *
+ * @param _loc Pointer to the path location.
+ * @return rtems_rfs_ino The inode number in the path location.
+ */
+#define rtems_rfs_rtems_get_pathloc_ino(_loc) \
+ ((rtems_rfs_ino) (intptr_t)((_loc)->node_access))
+
+/**
+ * Set the directory offset (doff) into the path location.
+ *
+ * @param _loc Pointer to the path location.
+ * @param _doff The doff to set in the path location.
+ */
+#define rtems_rfs_rtems_set_pathloc_doff(_loc, _doff) \
+ (_loc)->node_access_2 = (void*)(_doff)
+
+/**
+ * Get the directory offset (doff) given a path location.
+ *
+ * @param _loc Pointer to the path location.
+ * @return uin32_t The doff in the path location.
+ */
+#define rtems_rfs_rtems_get_pathloc_doff(_loc) \
+ ((uint32_t) (intptr_t)((_loc)->node_access_2))
+
+/**
+ * Get the ino from the I/O pointer.
+ *
+ * @param _iop The I/O pointer.
+ * @return
+ */
+#define rtems_rfs_rtems_get_iop_ino(_iop) \
+ ((intptr_t)(_iop)->file_info)
+
+/**
+ * Create the name of the handler's table given the type of handlers.
+ *
+ * @param _h The name of the handlers.
+ * @return label The name of the handler's table.
+ */
+#define rtems_rfs_rtems_handlers(_h) \
+ &rtems_rfs_rtems_ ## _h ## _handlers
+
+/**
+ * Evaluate the permissions of the inode's mode against the flags.
+ *
+ * @param inode The inode handler to check the mode, uid and gid.
+ * @param flags The flags to check permissions of.
+ * @retval true The permissions allow access to the inode.
+ * @retval false Access to the inode is not permitted.
+ */
+bool rtems_rfs_rtems_eval_perms (rtems_rfs_inode_handle* inode, int flags);
+
+/**
+ * Set the handlers in the path location based on the mode of the inode.
+ *
+ * @param loc Pointer to the path location to set the handlers in.
+ * @param inode The inode handle to check the mode of for the type of handlers.
+ * @retval true The handlers have been set.
+ * @retval false There are no handlers for the mode.
+ */
+bool rtems_rfs_rtems_set_handlers (rtems_filesystem_location_info_t* pathloc,
+ rtems_rfs_inode_handle* inode);
+
+/**
+ * Convert the system mode flags to inode mode flags.
+ *
+ * @param mode The system mode flags.
+ * @return uint16_t The inode mode flags.
+ */
+uint16_t rtems_rfs_rtems_imode (mode_t mode);
+
+/**
+ * Convert the inode mode flags to system mode flags.
+ *
+ * @param imode The inode mode flags
+ * @return mode_t The system mode flags.
+ */
+mode_t rtems_rfs_rtems_mode (int imode);
+
+/**
+ * Lock the RFS file system.
+ */
+static inline void
+ rtems_rfs_rtems_lock (rtems_rfs_file_system* fs)
+{
+ rtems_rfs_rtems_private* rtems = rtems_rfs_fs_user (fs);
+ rtems_rfs_mutex_lock (&rtems->access);
+}
+
+/**
+ * Unlock the RFS file system.
+ */
+static inline void
+ rtems_rfs_rtems_unlock (rtems_rfs_file_system* fs)
+{
+ rtems_rfs_rtems_private* rtems = rtems_rfs_fs_user (fs);
+ rtems_rfs_buffers_release (fs);
+ rtems_rfs_mutex_unlock (&rtems->access);
+}
+
+/**
+ * The handlers.
+ */
+extern const rtems_filesystem_file_handlers_r rtems_rfs_rtems_dir_handlers;
+extern const rtems_filesystem_file_handlers_r rtems_rfs_rtems_device_handlers;
+extern const rtems_filesystem_file_handlers_r rtems_rfs_rtems_link_handlers;
+extern const rtems_filesystem_file_handlers_r rtems_rfs_rtems_file_handlers;
+
+/**
+ * The following routine does a stat on a node.
+ *
+ * @param pathloc
+ * @param buf
+ * @return int
+ */
+int rtems_rfs_rtems_stat (rtems_filesystem_location_info_t* loc, struct stat* buf);
+
+/**
+ * File change mode routine.
+ *
+ * @param pathloc
+ * @param mode
+ * @return int
+ */
+int rtems_rfs_rtems_fchmod (rtems_filesystem_location_info_t* loc, mode_t mode);
+
+/**
+ * Routine to remove a node from the RFS file system.
+ *
+ * @param parent_pathloc
+ * @param pathloc
+ */
+int rtems_rfs_rtems_rmnod (rtems_filesystem_location_info_t* parent_pathloc,
+ rtems_filesystem_location_info_t* pathloc);
+
+/**
+ * The following routine does a sync on an inode node. Currently it flushes
+ * everything related to this device.
+ *
+ * @param iop
+ */
+int rtems_rfs_rtems_fdatasync (rtems_libio_t* iop);
+
+/**
+ * The following routine does a fcntl on an node.
+ *
+ * @param cmd
+ * @param iop
+ * @return int
+ */
+int rtems_rfs_rtems_fcntl (int cmd, rtems_libio_t* iop);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-shell.c b/cpukit/libfs/src/rfs/rtems-rfs-shell.c
new file mode 100644
index 0000000000..b1d25c2c67
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-shell.c
@@ -0,0 +1,666 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Shell Commands Support
+ */
+
+#include <string.h>
+
+#include <rtems/rfs/rtems-rfs-block.h>
+#include <rtems/rfs/rtems-rfs-buffer.h>
+#include <rtems/rfs/rtems-rfs-group.h>
+#include <rtems/rfs/rtems-rfs-inode.h>
+#include <rtems/rfs/rtems-rfs-dir.h>
+
+#include <sys/statvfs.h>
+
+#if __rtems__
+#include "rtems-rfs-rtems.h"
+#endif
+
+/**
+ * The type of the shell handlers we have.
+ */
+typedef int (*rtems_rfs_shell_handler) (rtems_rfs_file_system* fs, int argc, char *argv[]);
+
+/**
+ * Table of handlers we parse to invoke the command.
+ */
+typedef struct rtems_rfs_shell_cmd_t
+{
+ const char* name;
+ rtems_rfs_shell_handler handler;
+ const char* help;
+} rtems_rfs_shell_cmd;
+
+/**
+ * Lock the file system.
+ */
+static void
+rtems_rfs_shell_lock_rfs (rtems_rfs_file_system* fs)
+{
+#if __rtems__
+ rtems_rfs_rtems_lock (fs);
+#endif
+}
+
+/**
+ * Unlock the file system.
+ */
+static void
+rtems_rfs_shell_unlock_rfs (rtems_rfs_file_system* fs)
+{
+#if __rtems__
+ rtems_rfs_rtems_unlock (fs);
+#endif
+}
+
+/**
+ * Get the file system data from the specific path. Checks to make sure the path is
+ * pointing to a valid RFS file system.
+ */
+static int
+rtems_rfs_get_fs (const char* path, rtems_rfs_file_system** fs)
+{
+ struct statvfs sb;
+ int rc;
+
+ rc = statvfs (path, &sb);
+ if (rc < 0)
+ {
+ printf ("error: cannot statvfs path: %s: (%d) %s\n",
+ path, errno, strerror (errno));
+ return -1;
+ }
+
+ if (sb.f_fsid != RTEMS_RFS_SB_MAGIC)
+ {
+ printf ("error: path '%s' is not on an RFS file system\n", path);
+ return -1;
+ }
+
+#if __rtems__
+ /*
+ * Now find the path location on the file system. This will give the file
+ * system data.
+ */
+ {
+ rtems_filesystem_location_info_t pathloc;
+ rc = rtems_filesystem_evaluate_path (path, strlen (path), 0, &pathloc, true);
+ *fs = rtems_rfs_rtems_pathloc_dev (&pathloc);
+ rtems_filesystem_freenode (&pathloc);
+ }
+#endif
+
+ return rc;
+}
+
+static int
+rtems_rfs_shell_data (rtems_rfs_file_system* fs, int argc, char *argv[])
+{
+ size_t blocks;
+ size_t inodes;
+ int bpcent;
+ int ipcent;
+ int g;
+
+ printf ("RFS Filesystem Data\n");
+ printf (" flags: %08lx\n", fs->flags);
+#if 0
+ printf (" device: %08lx\n", rtems_rfs_fs_device (fs));
+#endif
+ printf (" blocks: %lu\n", rtems_rfs_fs_blocks (fs));
+ printf (" block size: %lu\n", rtems_rfs_fs_block_size (fs));
+ printf (" size: %llu\n", rtems_rfs_fs_size (fs));
+ printf (" media block size: %lu\n", rtems_rfs_fs_media_block_size (fs));
+ printf (" media size: %llu\n", rtems_rfs_fs_media_size (fs));
+ printf (" inodes: %lu\n", rtems_rfs_fs_inodes (fs));
+ printf (" bad blocks: %lu\n", fs->bad_blocks);
+ printf (" max. name length: %lu\n", rtems_rfs_fs_max_name (fs));
+ printf (" groups: %d\n", fs->group_count);
+ printf (" group blocks: %ld\n", fs->group_blocks);
+ printf (" group inodes: %ld\n", fs->group_inodes);
+ printf (" inodes per block: %ld\n", fs->inodes_per_block);
+ printf (" blocks per block: %ld\n", fs->blocks_per_block);
+ printf (" singly blocks: %ld\n", fs->block_map_singly_blocks);
+ printf (" doublly blocks: %ld\n", fs->block_map_doubly_blocks);
+ printf (" max. held buffers: %ld\n", fs->max_held_buffers);
+
+ rtems_rfs_shell_lock_rfs (fs);
+
+ blocks = 0;
+ inodes = 0;
+
+ for (g = 0; g < fs->group_count; g++)
+ {
+ rtems_rfs_group* group = &fs->groups[g];
+ blocks +=
+ rtems_rfs_bitmap_map_size(&group->block_bitmap) -
+ rtems_rfs_bitmap_map_free (&group->block_bitmap);
+ inodes +=
+ rtems_rfs_bitmap_map_size (&group->inode_bitmap) -
+ rtems_rfs_bitmap_map_free (&group->inode_bitmap);
+ }
+
+ rtems_rfs_shell_unlock_rfs (fs);
+
+ bpcent = (blocks * 1000) / rtems_rfs_fs_blocks (fs);
+ ipcent = (inodes * 1000) / rtems_rfs_fs_inodes (fs);
+
+ printf (" blocks used: %ld (%d.%d%%)\n",
+ blocks, bpcent / 10, bpcent % 10);
+ printf (" inodes used: %ld (%d.%d%%)\n",
+ inodes, ipcent / 10, ipcent % 10);
+
+ return 0;
+}
+
+static int
+rtems_rfs_shell_block (rtems_rfs_file_system* fs, int argc, char *argv[])
+{
+ rtems_rfs_buffer_handle buffer;
+ rtems_rfs_block_no block;
+ uint8_t* data;
+ bool state;
+ int b;
+ int rc;
+
+ if (argc <= 1)
+ {
+ printf ("error: no block number provided\n");
+ return 1;
+ }
+
+ block = strtoul (argv[1], 0, 0);
+
+ rtems_rfs_shell_lock_rfs (fs);
+
+ rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: testing block state: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ printf (" %5lu: block %s\n", block, state ? "allocated" : "free");
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: opening buffer handle: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: requesting buffer handle: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ for (b = 0, data = rtems_rfs_buffer_data (&buffer);
+ b < rtems_rfs_fs_block_size (fs);
+ b++, data++)
+ {
+ int mod = b % 16;
+ if (mod == 0)
+ {
+ if (b)
+ printf ("\n");
+ printf ("%04x ", b);
+ }
+ if (mod == 8)
+ printf (" ");
+ printf ("%02x ", *data);
+ }
+
+ printf ("\n");
+
+ rc = rtems_rfs_buffer_handle_close (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: closing buffer handle: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ rtems_rfs_shell_unlock_rfs (fs);
+
+ return 0;
+}
+
+static int
+rtems_rfs_shell_inode (rtems_rfs_file_system* fs, int argc, char *argv[])
+{
+ rtems_rfs_ino start;
+ rtems_rfs_ino end;
+ rtems_rfs_ino total;
+ rtems_rfs_ino ino;
+ bool show_all;
+ bool error_check_only;
+ bool forced;
+ bool have_start;
+ bool have_end;
+ int arg;
+ int b;
+ int rc;
+
+ total = fs->group_inodes * fs->group_count;
+ start = RTEMS_RFS_ROOT_INO;
+ end = total - 1;
+ show_all = false;
+ error_check_only = false;
+ forced = false;
+ have_start = have_end = false;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ switch (argv[arg][1])
+ {
+ case 'a':
+ show_all = true;
+ break;
+ case 'e':
+ error_check_only = true;
+ break;
+ case 'f':
+ forced = true;
+ break;
+ default:
+ printf ("warning: option ignored: %s\n", argv[arg]);
+ break;
+ }
+ }
+ else
+ {
+ if (have_end && have_start)
+ printf ("warning: option ignored: %s\n", argv[arg]);
+ else if (!have_start)
+ {
+ start = end = strtoul (argv[arg], 0, 0);
+ have_start = true;
+ }
+ else
+ {
+ end = strtoul (argv[arg], 0, 0);
+ have_end = true;
+ }
+ }
+ }
+
+ if ((start < 0) || (end < 0) ||
+ (start >= total) || (end >= total))
+ {
+ printf ("error: inode out of range (0->%ld).\n", total - 1);
+ return 1;
+ }
+
+ rtems_rfs_shell_lock_rfs (fs);
+
+ for (ino = start; ino <= end; ino++)
+ {
+ rtems_rfs_inode_handle inode;
+ bool allocated;
+
+ rc = rtems_rfs_group_bitmap_test (fs, true, ino, &allocated);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: testing inode state: ino=%lu: (%d) %s\n",
+ ino, rc, strerror (rc));
+ return 1;
+ }
+
+ if (show_all || allocated)
+ {
+ uint16_t mode;
+ bool error;
+
+ rc = rtems_rfs_inode_open (fs, ino, &inode, true);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: opening inode handle: ino=%lu: (%d) %s\n",
+ ino, rc, strerror (rc));
+ return 1;
+ }
+
+ error = false;
+
+ mode = rtems_rfs_inode_get_mode (&inode);
+
+ if (error_check_only)
+ {
+ if (!RTEMS_RFS_S_ISDIR (mode) &&
+ !RTEMS_RFS_S_ISCHR (mode) &&
+ !RTEMS_RFS_S_ISBLK (mode) &&
+ !RTEMS_RFS_S_ISREG (mode) &&
+ !RTEMS_RFS_S_ISLNK (mode))
+ error = true;
+ else
+ {
+#if NEED_TO_HANDLE_DIFFERENT_TYPES
+ int b;
+ for (b = 0; b < RTEMS_RFS_INODE_BLOCKS; b++)
+ {
+ uint32_t block;
+ block = rtems_rfs_inode_get_block (&inode, b);
+ if ((block <= RTEMS_RFS_SUPERBLOCK_SIZE) ||
+ (block >= rtems_rfs_fs_blocks (fs)))
+ error = true;
+ }
+#endif
+ }
+ }
+
+ if (!error_check_only || error)
+ {
+ printf (" %5lu: pos=%06lu:%04lx %c ",
+ ino, rtems_rfs_buffer_bnum (&inode.buffer),
+ inode.offset * sizeof (rtems_rfs_inode),
+ allocated ? 'A' : 'F');
+
+ if (!allocated && !forced)
+ printf (" --\n");
+ else
+ {
+ const char* type;
+ type = "UKN";
+ if (RTEMS_RFS_S_ISDIR (mode))
+ type = "DIR";
+ else if (RTEMS_RFS_S_ISCHR (mode))
+ type = "CHR";
+ else if (RTEMS_RFS_S_ISBLK (mode))
+ type = "BLK";
+ else if (RTEMS_RFS_S_ISREG (mode))
+ type = "REG";
+ else if (RTEMS_RFS_S_ISLNK (mode))
+ type = "LNK";
+ printf ("links=%03i mode=%04x (%s/%03o) bo=%04u bc=%04lu b=[",
+ rtems_rfs_inode_get_links (&inode),
+ mode, type, mode & ((1 << 10) - 1),
+ rtems_rfs_inode_get_block_offset (&inode),
+ rtems_rfs_inode_get_block_count (&inode));
+ for (b = 0; b < (RTEMS_RFS_INODE_BLOCKS - 1); b++)
+ printf ("%lu ", rtems_rfs_inode_get_block (&inode, b));
+ printf ("%lu]\n", rtems_rfs_inode_get_block (&inode, b));
+ }
+ }
+
+ rc = rtems_rfs_inode_close (fs, &inode);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: closing inode handle: ino=%lu: (%d) %s\n",
+ ino, rc, strerror (rc));
+ return 1;
+ }
+ }
+ }
+
+ rtems_rfs_shell_unlock_rfs (fs);
+
+ return 0;
+}
+
+static int
+rtems_rfs_shell_dir (rtems_rfs_file_system* fs, int argc, char *argv[])
+{
+ rtems_rfs_buffer_handle buffer;
+ rtems_rfs_block_no block;
+ uint8_t* data;
+ bool state;
+ int entry;
+ int b;
+ int rc;
+
+ if (argc <= 1)
+ {
+ printf ("error: no block number provided\n");
+ return 1;
+ }
+
+ block = strtoul (argv[1], 0, 0);
+
+ rtems_rfs_shell_lock_rfs (fs);
+
+ rc = rtems_rfs_group_bitmap_test (fs, false, block, &state);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: testing block state: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ printf (" %5lu: block %s\n", block, state ? "allocated" : "free");
+
+ rc = rtems_rfs_buffer_handle_open (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: opening buffer handle: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ rc = rtems_rfs_buffer_handle_request (fs, &buffer, block, true);
+ if (rc > 0)
+ {
+ rtems_rfs_buffer_handle_close (fs, &buffer);
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: requesting buffer handle: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ b = 0;
+ entry = 1;
+ data = rtems_rfs_buffer_data (&buffer);
+
+ while (b < (rtems_rfs_fs_block_size (fs) - RTEMS_RFS_DIR_ENTRY_SIZE - 1))
+ {
+ rtems_rfs_ino eino;
+ int elength;
+ int length;
+ int c;
+
+ eino = rtems_rfs_dir_entry_ino (data);
+ elength = rtems_rfs_dir_entry_length (data);
+
+ if (elength == RTEMS_RFS_DIR_ENTRY_EMPTY)
+ break;
+
+ if ((elength < RTEMS_RFS_DIR_ENTRY_SIZE) ||
+ (elength >= rtems_rfs_fs_max_name (fs)))
+ {
+ printf (" %5d: entry length appears corrupt: %d\n", entry, elength);
+ break;
+ }
+
+ if ((eino < RTEMS_RFS_ROOT_INO) || (eino >= rtems_rfs_fs_inodes (fs)))
+ {
+ printf (" %5d: entry ino appears corrupt: ino=%ld\n", entry, eino);
+ break;
+ }
+
+ length = elength - RTEMS_RFS_DIR_ENTRY_SIZE;
+
+ printf (" %5d: %04x inode=%-6u hash=%08x name[%03u]=",
+ entry, b,
+ rtems_rfs_dir_entry_ino (data),
+ rtems_rfs_dir_entry_hash (data),
+ length);
+
+ if (length > 50)
+ length = 50;
+
+ for (c = 0; c < length; c++)
+ printf ("%c", data[RTEMS_RFS_DIR_ENTRY_SIZE + c]);
+ if (length < elength - RTEMS_RFS_DIR_ENTRY_SIZE)
+ printf ("...");
+ printf ("\n");
+
+ b += elength;
+ data += elength;
+ entry++;
+ }
+
+ rc = rtems_rfs_buffer_handle_close (fs, &buffer);
+ if (rc > 0)
+ {
+ rtems_rfs_shell_unlock_rfs (fs);
+ printf ("error: closing buffer handle: block=%lu: (%d) %s\n",
+ block, rc, strerror (rc));
+ return 1;
+ }
+
+ rtems_rfs_shell_unlock_rfs (fs);
+
+ return 0;
+}
+
+static int
+rtems_rfs_shell_group (rtems_rfs_file_system* fs, int argc, char *argv[])
+{
+ int start;
+ int end;
+ int g;
+
+ start = 0;
+ end = fs->group_count - 1;
+
+ switch (argc)
+ {
+ case 1:
+ break;
+ case 2:
+ start = end = strtoul (argv[1], 0, 0);
+ break;
+ case 3:
+ start = strtoul (argv[1], 0, 0);
+ end = strtoul (argv[2], 0, 0);
+ break;
+ default:
+ printf ("error: too many arguments.\n");
+ return 1;
+ }
+
+ if ((start < 0) || (end < 0) ||
+ (start >= fs->group_count) || (end >= fs->group_count))
+ {
+ printf ("error: group out of range (0->%d).\n", fs->group_count);
+ return 1;
+ }
+
+ rtems_rfs_shell_lock_rfs (fs);
+
+ for (g = start; g <= end; g++)
+ {
+ rtems_rfs_group* group = &fs->groups[g];
+ size_t blocks;
+ size_t inodes;
+ blocks = group->size - rtems_rfs_bitmap_map_free (&group->block_bitmap);
+ inodes = fs->group_inodes - rtems_rfs_bitmap_map_free (&group->inode_bitmap);
+ printf (" %4d: base=%-7lu size=%-6lu blocks=%-5lu (%3lu%%) inode=%-5lu (%3lu%%)\n",
+ g, group->base, group->size,
+ blocks, (blocks * 100) / group->size,
+ inodes, (inodes * 100) / fs->group_inodes);
+ }
+
+ rtems_rfs_shell_unlock_rfs (fs);
+
+ return 0;
+}
+
+
+void
+rtems_rfs_shell_usage (const char* arg)
+{
+ printf ("%s: RFS debugger\n", arg);
+ printf (" %s [-hl] <path> <command>\n", arg);
+ printf (" where:\n");
+ printf (" path: Path to the mounted RFS file system\n");
+ printf (" command: A debugger command. See -l for a list plus help.\n");
+ printf (" -h: This help\n");
+ printf (" -l: The debugger command list.\n");
+}
+
+int
+rtems_rfs_shell_debugrfs (int argc, char *argv[])
+{
+ const rtems_rfs_shell_cmd table[] =
+ {
+ { "block", rtems_rfs_shell_block,
+ "Display the contents of a block, block <bno>, block <bno>..<bno>" },
+ { "data", rtems_rfs_shell_data,
+ "Display file system data, data" },
+ { "dir", rtems_rfs_shell_dir,
+ "Display a block as a table for directory entrie, dir <bno>" },
+ { "group", rtems_rfs_shell_group,
+ "Display the group data of a file system, group, group <group>, group <start> <end>" },
+ { "inode", rtems_rfs_shell_inode,
+ "Display an inode, inode <ino>, inode> <ino>..<ino>" }
+ };
+
+ int arg;
+ int t;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] != '-')
+ break;
+
+ switch (argv[arg][1])
+ {
+ case 'h':
+ rtems_rfs_shell_usage (argv[0]);
+ return 0;
+ case 'l':
+ printf ("%s: commands are:\n", argv[0]);
+ for (t = 0; t < (sizeof (table) / sizeof (const rtems_rfs_shell_cmd)); t++)
+ printf (" %s\t\t%s\n", table[t].name, table[t].help);
+ return 0;
+ default:
+ printf ("error: unknown option: %s\n", argv[arg]);
+ return 1;
+ }
+ }
+
+ if ((argc - arg) < 2)
+ printf ("error: you need at least a path and command, try %s -h\n", argv[0]);
+ else
+ {
+ rtems_rfs_file_system* fs;
+ if (rtems_rfs_get_fs (argv[arg], &fs) == 0)
+ {
+ for (t = 0; t < (sizeof (table) / sizeof (const rtems_rfs_shell_cmd)); t++)
+ if (strcmp (argv[arg + 1], table[t].name) == 0)
+ return table[t].handler (fs, argc - 2, argv + 2);
+ printf ("error: command not found: %s\n", argv[arg + 1]);
+ }
+ }
+
+ return 1;
+}
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-shell.h b/cpukit/libfs/src/rfs/rtems-rfs-shell.h
new file mode 100644
index 0000000000..31a3dc8266
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-shell.h
@@ -0,0 +1,35 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Shell commands provide a CLI interface to support and
+ * development od the RFS file system.
+ */
+
+#if !defined (_RTEMS_RFS_SHELL_H_)
+#define _RTEMS_RFS_SHELL_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+/**
+ * The shell command for the RFS debugger.
+ *
+ * @param argc The argument count.
+ * @param argv The argument variables.
+ * @return int The exit code for the command. A 0 is no error.
+ */
+int rtems_rfs_shell_debugrfs (int argc, char *argv[]);
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-trace.c b/cpukit/libfs/src/rfs/rtems-rfs-trace.c
new file mode 100644
index 0000000000..f344ac9ec6
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-trace.c
@@ -0,0 +1,154 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Trace Support
+ */
+
+#include <string.h>
+#include <rtems/rfs/rtems-rfs-trace.h>
+
+#if RTEMS_RFS_TRACE
+static rtems_rfs_trace_mask rtems_rfs_trace_flags;
+
+bool
+rtems_rfs_trace (rtems_rfs_trace_mask mask)
+{
+ bool result = false;
+ if (mask & rtems_rfs_trace_flags)
+ result = true;
+ return result;
+}
+
+rtems_rfs_trace_mask
+rtems_rfs_trace_set_mask (rtems_rfs_trace_mask mask)
+{
+ rtems_rfs_trace_mask state = rtems_rfs_trace_flags;
+ rtems_rfs_trace_flags |= mask;
+ return state;
+}
+
+rtems_rfs_trace_mask
+rtems_rfs_trace_clear_mask (rtems_rfs_trace_mask mask)
+{
+ rtems_rfs_trace_mask state = rtems_rfs_trace_flags;
+ rtems_rfs_trace_flags &= ~mask;
+ return state;
+}
+
+int
+rtems_rfs_trace_shell_command (int argc, char *argv[])
+{
+ const char* table[] =
+ {
+ "open",
+ "close",
+ "mutex",
+ "buffer-open",
+ "buffer-close",
+ "buffer-sync",
+ "buffer-release",
+ "buffer-chains",
+ "buffer-handle-request",
+ "buffer-handle-release",
+ "buffer-setblksize",
+ "buffers-release",
+ "block-find",
+ "block-map-grow",
+ "block-map-shrink",
+ "group-open",
+ "group-close",
+ "group-bitmaps",
+ "inode-open",
+ "inode-close",
+ "inode-load",
+ "inode-unload",
+ "inode-create",
+ "link",
+ "unlink",
+ "dir-lookup-ino",
+ "dir-lookup-ino-check",
+ "dir-lookup-ino-found",
+ "dir-add-entry",
+ "dir-del-entry",
+ "dir-read",
+ "dir-empty",
+ "symlink",
+ "symlink-read",
+ "file-open",
+ "file-close",
+ "file-io"
+ };
+
+ rtems_rfs_trace_mask set_value = 0;
+ rtems_rfs_trace_mask clear_value = 0;
+ bool set = true;
+ int arg;
+ int t;
+
+ for (arg = 1; arg < argc; arg++)
+ {
+ if (argv[arg][0] == '-')
+ {
+ switch (argv[arg][1])
+ {
+ case 'h':
+ printf ("usage: %s [-hl] [set/clear] [flags]\n", argv[0]);
+ return 0;
+ case 'l':
+ printf ("%s: valid flags to set or clear are:\n", argv[0]);
+ for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++)
+ printf (" %s\n", table[t]);
+ return 0;
+ default:
+ printf ("error: unknown option\n");
+ return 1;
+ }
+ }
+ else
+ {
+ if (strcmp (argv[arg], "set") == 0)
+ set = true;
+ if (strcmp (argv[arg], "clear") == 0)
+ set = false;
+ else if (strcmp (argv[arg], "all") == 0)
+ {
+ if (set)
+ set_value = RTEMS_RFS_TRACE_ALL;
+ else
+ clear_value = RTEMS_RFS_TRACE_ALL;
+ }
+ else
+ {
+ for (t = 0; t < (sizeof (table) / sizeof (const char*)); t++)
+ {
+ if (strcmp (argv[arg], table[t]) == 0)
+ {
+ if (set)
+ set_value = 1 << t;
+ else
+ clear_value = 1 << t;
+ break;
+ }
+ }
+ }
+
+ rtems_rfs_trace_flags |= set_value;
+ rtems_rfs_trace_flags &= ~clear_value;
+ }
+ }
+
+ return 0;
+}
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs-trace.h b/cpukit/libfs/src/rfs/rtems-rfs-trace.h
new file mode 100644
index 0000000000..516bfe8e8f
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs-trace.h
@@ -0,0 +1,126 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File Systems Trace manages the trace and debugging features of the
+ * RTEMS RFS file system. The design allows all tracing code and strings to be
+ * removed from the target code for small footprint systems.
+ */
+
+#if !defined (_RTEMS_RFS_TRACE_H_)
+#define _RTEMS_RFS_TRACE_H_
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/**
+ * Is tracing enabled ?
+ */
+#define RTEMS_RFS_TRACE 0
+
+/**
+ * The type of the mask.
+ */
+typedef uint64_t rtems_rfs_trace_mask;
+
+/**
+ * List of tracing bits for the various parts of the file system.
+ */
+#define RTEMS_RFS_TRACE_ALL (0xffffffffffffffffULL)
+#define RTEMS_RFS_TRACE_OPEN (1ULL << 0)
+#define RTEMS_RFS_TRACE_CLOSE (1ULL << 1)
+#define RTEMS_RFS_TRACE_MUTEX (1ULL << 2)
+#define RTEMS_RFS_TRACE_BUFFER_OPEN (1ULL << 3)
+#define RTEMS_RFS_TRACE_BUFFER_CLOSE (1ULL << 4)
+#define RTEMS_RFS_TRACE_BUFFER_SYNC (1ULL << 5)
+#define RTEMS_RFS_TRACE_BUFFER_RELEASE (1ULL << 6)
+#define RTEMS_RFS_TRACE_BUFFER_CHAINS (1ULL << 7)
+#define RTEMS_RFS_TRACE_BUFFER_HANDLE_REQUEST (1ULL << 8)
+#define RTEMS_RFS_TRACE_BUFFER_HANDLE_RELEASE (1ULL << 9)
+#define RTEMS_RFS_TRACE_BUFFER_SETBLKSIZE (1ULL << 10)
+#define RTEMS_RFS_TRACE_BUFFERS_RELEASE (1ULL << 11)
+#define RTEMS_RFS_TRACE_BLOCK_FIND (1ULL << 12)
+#define RTEMS_RFS_TRACE_BLOCK_MAP_GROW (1ULL << 13)
+#define RTEMS_RFS_TRACE_BLOCK_MAP_SHRINK (1ULL << 14)
+#define RTEMS_RFS_TRACE_GROUP_OPEN (1ULL << 15)
+#define RTEMS_RFS_TRACE_GROUP_CLOSE (1ULL << 16)
+#define RTEMS_RFS_TRACE_GROUP_BITMAPS (1ULL << 17)
+#define RTEMS_RFS_TRACE_INODE_OPEN (1ULL << 18)
+#define RTEMS_RFS_TRACE_INODE_CLOSE (1ULL << 19)
+#define RTEMS_RFS_TRACE_INODE_LOAD (1ULL << 20)
+#define RTEMS_RFS_TRACE_INODE_UNLOAD (1ULL << 21)
+#define RTEMS_RFS_TRACE_INODE_CREATE (1ULL << 22)
+#define RTEMS_RFS_TRACE_LINK (1ULL << 23)
+#define RTEMS_RFS_TRACE_UNLINK (1ULL << 24)
+#define RTEMS_RFS_TRACE_DIR_LOOKUP_INO (1ULL << 25)
+#define RTEMS_RFS_TRACE_DIR_LOOKUP_INO_CHECK (1ULL << 26)
+#define RTEMS_RFS_TRACE_DIR_LOOKUP_INO_FOUND (1ULL << 27)
+#define RTEMS_RFS_TRACE_DIR_ADD_ENTRY (1ULL << 28)
+#define RTEMS_RFS_TRACE_DIR_DEL_ENTRY (1ULL << 29)
+#define RTEMS_RFS_TRACE_DIR_READ (1ULL << 30)
+#define RTEMS_RFS_TRACE_DIR_EMPTY (1ULL << 31)
+#define RTEMS_RFS_TRACE_SYMLINK (1ULL << 32)
+#define RTEMS_RFS_TRACE_SYMLINK_READ (1ULL << 33)
+#define RTEMS_RFS_TRACE_FILE_OPEN (1ULL << 34)
+#define RTEMS_RFS_TRACE_FILE_CLOSE (1ULL << 35)
+#define RTEMS_RFS_TRACE_FILE_IO (1ULL << 36)
+#define RTEMS_RFS_TRACE_FILE_SET (1ULL << 37)
+
+/**
+ * Call to check if this part is bring traced. If RTEMS_RFS_TRACE is defined to
+ * 0 the code is dead code elminiated when built with -Os, -O2, or higher.
+ *
+ * @param mask The part of the API to trace.
+ * @retval true Tracing is active for the mask.
+ * @retval false Do not trace.
+ */
+#if RTEMS_RFS_TRACE
+bool rtems_rfs_trace (rtems_rfs_trace_mask mask);
+#else
+#define rtems_rfs_trace(_m) (0)
+#endif
+
+/**
+ * Set the mask.
+ *
+ * @param mask The mask bits to set.
+ * @return The previous mask.
+ */
+#if RTEMS_RFS_TRACE
+rtems_rfs_trace_mask rtems_rfs_trace_set_mask (rtems_rfs_trace_mask mask);
+#else
+#define rtems_rfs_trace_set_mask(_m)
+#endif
+
+/**
+ * Clear the mask.
+ *
+ * @param mask The mask bits to clear.
+ * @return The previous mask.
+ */
+#if RTEMS_RFS_TRACE
+rtems_rfs_trace_mask rtems_rfs_trace_clear_mask (rtems_rfs_trace_mask mask);
+#else
+#define rtems_rfs_trace_clear_mask(_m)
+#endif
+
+/**
+ * Add shell trace shell command.
+ */
+#if RTEMS_RFS_TRACE
+int rtems_rfs_trace_shell_command (int argc, char *argv[]);
+#endif
+
+#endif
diff --git a/cpukit/libfs/src/rfs/rtems-rfs.h b/cpukit/libfs/src/rfs/rtems-rfs.h
new file mode 100644
index 0000000000..b0e5a6c5e2
--- /dev/null
+++ b/cpukit/libfs/src/rfs/rtems-rfs.h
@@ -0,0 +1,35 @@
+/*
+ * COPYRIGHT (c) 2010 Chris Johns <chrisj@rtems.org>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+/**
+ * @file
+ *
+ * @ingroup rtems-rfs
+ *
+ * RTEMS File System
+ *
+ */
+
+#if !defined(RTEMS_RFS_DEFINED)
+#define RTEMS_RFS_DEFINED
+
+#include <rtems.h>
+#include <rtems/fs.h>
+
+/**
+ * File ops table for the RFS file system.
+ */
+const rtems_filesystem_operations_table rtems_rfs_ops;
+
+/**
+ * Initialise the RFS File system.
+ */
+int rtems_rfs_initialise (rtems_filesystem_mount_table_entry_t *mt_entry);
+
+#endif
diff --git a/cpukit/libmisc/shell/main_ls.c b/cpukit/libmisc/shell/main_ls.c
index b60477ff79..08072fb723 100644
--- a/cpukit/libmisc/shell/main_ls.c
+++ b/cpukit/libmisc/shell/main_ls.c
@@ -573,8 +573,9 @@ display(rtems_shell_ls_globals* globals, FTSENT *p, FTSENT *list)
maxlen = cur->fts_namelen;
if (needstats) {
sp = cur->fts_statp;
- size = ((uint64_t) sp->st_blocks) * sp->st_blksize;
- if (size < 0x100000000ULL)
+ if (sp->st_size < 0)
+ size = sp->st_size * -1;
+ else
size = sp->st_size;
if (sp->st_blocks > maxblock)
maxblock = sp->st_blocks;
diff --git a/cpukit/libmisc/shell/print-ls.c b/cpukit/libmisc/shell/print-ls.c
index 192d8f11b8..56e7b149d7 100644
--- a/cpukit/libmisc/shell/print-ls.c
+++ b/cpukit/libmisc/shell/print-ls.c
@@ -162,9 +162,10 @@ printlong(rtems_shell_ls_globals* globals, DISPLAY *dp)
} else {
#endif
{
- unsigned long long size = sp->st_blocks;
- size *= sp->st_blksize;
- if (size < 0x100000000ULL)
+ unsigned long long size;
+ if (sp->st_size < 0)
+ size = sp->st_size * -1;
+ else
size = sp->st_size;
(void)printf("%*llu ", dp->s_size, size);
}
diff --git a/cpukit/libnetworking/nfs/bootp_subr.c b/cpukit/libnetworking/nfs/bootp_subr.c
index 7a0e8901f6..34754ac77a 100644
--- a/cpukit/libnetworking/nfs/bootp_subr.c
+++ b/cpukit/libnetworking/nfs/bootp_subr.c
@@ -152,8 +152,6 @@ bootpc_adjust_interface(struct ifreq *ireq,struct socket *so,
struct sockaddr_in *gw,
struct proc *procp);
-void bootpc_init(int update_files);
-
#ifdef BOOTP_DEBUG
void
bootpboot_p_sa(struct sockaddr *sa, struct sockaddr *ma)
@@ -463,7 +461,7 @@ bootpc_call(
goto gotreply; /* break two levels */
} /* while secs */
- } /* forever send/receive */
+ } /* send/receive a number of times then return an error */
{
uint32_t addr = ntohl(sin->sin_addr.s_addr);
printf("BOOTP timeout for server %lu.%lu.%lu.%lu\n",
@@ -943,8 +941,8 @@ processOptions (unsigned char *optbuf, int optbufSize)
#define EALEN 6
-void
-bootpc_init(int update_files)
+bool
+bootpc_init(bool update_files, bool forever)
{
struct bootp_packet call;
struct bootp_packet reply;
@@ -965,7 +963,7 @@ bootpc_init(int update_files)
* If already filled in, don't touch it here
*/
if (nfs_diskless_valid)
- return;
+ return true;
/*
* If we are to update the files create the root
@@ -991,7 +989,7 @@ bootpc_init(int update_files)
break;
if (ifp == NULL) {
printf("bootpc_init: no suitable interface\n");
- return;
+ return false;
}
bzero(&ireq,sizeof(ireq));
sprintf(ireq.ifr_name, "%s%d", ifp->if_name,ifp->if_unit);
@@ -1000,28 +998,31 @@ bootpc_init(int update_files)
if ((error = socreate(AF_INET, &so, SOCK_DGRAM, 0,procp)) != 0) {
printf("bootpc_init: socreate, error=%d", error);
- return;
+ return false;
}
if (bootpc_fakeup_interface(&ireq,so,procp) != 0) {
- return;
+ soclose(so);
+ return false;
}
/* Get HW address */
for (ifa = ifp->if_addrlist;ifa; ifa = ifa->ifa_next)
if (ifa->ifa_addr->sa_family == AF_LINK &&
- (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
- sdl->sdl_type == IFT_ETHER)
+ (sdl = ((struct sockaddr_dl *) ifa->ifa_addr)) &&
+ sdl->sdl_type == IFT_ETHER)
break;
if (!sdl) {
printf("bootpc: Unable to find HW address\n");
- return;
+ soclose(so);
+ return false;
}
if (sdl->sdl_alen != EALEN ) {
printf("bootpc: HW address len is %d, expected value is %d\n",
sdl->sdl_alen,EALEN);
- return;
+ soclose(so);
+ return false;
}
printf("bootpc hw address is ");
@@ -1036,32 +1037,39 @@ bootpc_init(int update_files)
bootpboot_p_iflist();
bootpboot_p_rtlist();
#endif
+
+ while (true) {
+ bzero((caddr_t) &call, sizeof(call));
+
+ /* bootpc part */
+ call.op = 1; /* BOOTREQUEST */
+ call.htype= 1; /* 10mb ethernet */
+ call.hlen=sdl->sdl_alen; /* Hardware address length */
+ call.hops=0;
+ xid++;
+ call.xid = txdr_unsigned(xid);
+ bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
- bzero((caddr_t) &call, sizeof(call));
-
- /* bootpc part */
- call.op = 1; /* BOOTREQUEST */
- call.htype= 1; /* 10mb ethernet */
- call.hlen=sdl->sdl_alen; /* Hardware address length */
- call.hops=0;
- xid++;
- call.xid = txdr_unsigned(xid);
- bcopy(LLADDR(sdl),&call.chaddr,sdl->sdl_alen);
-
- call.vend[0]=99;
- call.vend[1]=130;
- call.vend[2]=83;
- call.vend[3]=99;
- call.vend[4]=255;
+ call.vend[0]=99;
+ call.vend[1]=130;
+ call.vend[2]=83;
+ call.vend[3]=99;
+ call.vend[4]=255;
- call.secs = 0;
- call.flags = htons(0x8000); /* We need an broadcast answer */
+ call.secs = 0;
+ call.flags = htons(0x8000); /* We need an broadcast answer */
- error = bootpc_call(&call,&reply,procp);
+ error = bootpc_call(&call,&reply,procp);
- if (error) {
+ if (!error)
+ break;
+
printf("BOOTP call failed -- error %d", error);
- return;
+
+ if (!forever) {
+ soclose(so);
+ return false;
+ }
}
/*
@@ -1200,4 +1208,6 @@ bootpc_init(int update_files)
error = bootpc_adjust_interface(&ireq,so,
&myaddr,&dhcp_netmask,&dhcp_gw,procp);
soclose(so);
+
+ return true;
}
diff --git a/cpukit/libnetworking/rtems/rtems_bootp.c b/cpukit/libnetworking/rtems/rtems_bootp.c
index 23c6801757..caf2faa6e2 100644
--- a/cpukit/libnetworking/rtems/rtems_bootp.c
+++ b/cpukit/libnetworking/rtems/rtems_bootp.c
@@ -18,9 +18,12 @@
void
rtems_bsdnet_do_bootp (void)
{
+ bool ok;
rtems_bsdnet_semaphore_obtain ();
- bootpc_init (FALSE);
+ ok = bootpc_init (false, true);
rtems_bsdnet_semaphore_release ();
+ if (!ok)
+ panic ("rtems_bsdnet_do_bootp: bootp failed");
}
/*
@@ -30,7 +33,10 @@ rtems_bsdnet_do_bootp (void)
void
rtems_bsdnet_do_bootp_and_rootfs (void)
{
+ bool ok;
rtems_bsdnet_semaphore_obtain ();
- bootpc_init (TRUE);
+ ok = bootpc_init (true, true);
rtems_bsdnet_semaphore_release ();
+ if (!ok)
+ panic ("rtems_bsdnet_do_bootp_and_rootfs: bootp failed");
}
diff --git a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h
index bb3633813a..a22a22391c 100644
--- a/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h
+++ b/cpukit/libnetworking/rtems/rtems_bsdnet_internal.h
@@ -179,7 +179,7 @@ void domaininit (void *);
void ifinit (void *);
void ipintr (void);
void arpintr (void);
-void bootpc_init(int );
+bool bootpc_init(bool, bool);
int socket (int, int, int);
int ioctl (int, ioctl_command_t, ...);
diff --git a/cpukit/preinstall.am b/cpukit/preinstall.am
index a3bd6a9b31..c1be034fab 100644
--- a/cpukit/preinstall.am
+++ b/cpukit/preinstall.am
@@ -172,6 +172,83 @@ $(PROJECT_INCLUDE)/rtems/dosfs.h: libfs/src/dosfs/dosfs.h $(PROJECT_INCLUDE)/rte
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/dosfs.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/dosfs.h
endif
+$(PROJECT_INCLUDE)/rtems/rtems-rfs.h: libfs/src/rfs/rtems-rfs.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-rfs.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-rfs.h
+
+$(PROJECT_INCLUDE)/rtems/rtems-rfs-format.h: libfs/src/rfs/rtems-rfs-format.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-rfs-format.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-rfs-format.h
+
+$(PROJECT_INCLUDE)/rtems/rtems-rfs-shell.h: libfs/src/rfs/rtems-rfs-shell.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rtems-rfs-shell.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rtems-rfs-shell.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp):
+ @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems/rfs
+ @: > $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+PREINSTALL_DIRS += $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-bitmaps.h: libfs/src/rfs/rtems-rfs-bitmaps.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-bitmaps.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-bitmaps.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-block-pos.h: libfs/src/rfs/rtems-rfs-block-pos.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-block-pos.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-block-pos.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-block.h: libfs/src/rfs/rtems-rfs-block.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-block.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-block.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-buffer.h: libfs/src/rfs/rtems-rfs-buffer.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-buffer.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-buffer.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-data.h: libfs/src/rfs/rtems-rfs-data.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-data.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-data.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-dir.h: libfs/src/rfs/rtems-rfs-dir.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-dir.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-dir.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-dir-hash.h: libfs/src/rfs/rtems-rfs-dir-hash.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-dir-hash.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-dir-hash.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file.h: libfs/src/rfs/rtems-rfs-file.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file-system-fwd.h: libfs/src/rfs/rtems-rfs-file-system-fwd.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file-system-fwd.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file-system-fwd.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file-system.h: libfs/src/rfs/rtems-rfs-file-system.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file-system.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-file-system.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-group.h: libfs/src/rfs/rtems-rfs-group.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-group.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-group.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-inode.h: libfs/src/rfs/rtems-rfs-inode.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-inode.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-inode.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-link.h: libfs/src/rfs/rtems-rfs-link.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-link.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-link.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-mutex.h: libfs/src/rfs/rtems-rfs-mutex.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-mutex.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-mutex.h
+
+$(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-trace.h: libfs/src/rfs/rtems-rfs-trace.h $(PROJECT_INCLUDE)/rtems/rfs/$(dirstamp)
+ $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-trace.h
+PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/rfs/rtems-rfs-trace.h
+
$(PROJECT_INCLUDE)/rtems/bdbuf.h: libblock/include/rtems/bdbuf.h $(PROJECT_INCLUDE)/rtems/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bdbuf.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bdbuf.h
diff --git a/cpukit/wrapup/Makefile.am b/cpukit/wrapup/Makefile.am
index 1aef744fb3..9c60f8eee3 100644
--- a/cpukit/wrapup/Makefile.am
+++ b/cpukit/wrapup/Makefile.am
@@ -32,6 +32,7 @@ if LIBDOSFS
TMP_LIBS += ../libfs/libdosfs.a
endif
TMP_LIBS += ../libfs/libimfs.a
+TMP_LIBS += ../libfs/librfs.a
TMP_LIBS += ../libmisc/libmonitor.a
TMP_LIBS += ../libmisc/libuntar.a