summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--c/src/exec/libfs/ChangeLog17
-rw-r--r--c/src/exec/libfs/configure.ac3
-rw-r--r--c/src/exec/libfs/src/Makefile.am2
-rw-r--r--c/src/exec/libfs/src/dosfs/.cvsignore6
-rw-r--r--c/src/exec/libfs/src/dosfs/Makefile.am80
-rw-r--r--c/src/exec/libfs/src/dosfs/dosfs.h31
-rw-r--r--c/src/exec/libfs/src/dosfs/fat.c695
-rw-r--r--c/src/exec/libfs/src/dosfs/fat.h489
-rw-r--r--c/src/exec/libfs/src/dosfs/fat_fat_operations.c445
-rw-r--r--c/src/exec/libfs/src/dosfs/fat_fat_operations.h58
-rw-r--r--c/src/exec/libfs/src/dosfs/fat_file.c979
-rw-r--r--c/src/exec/libfs/src/dosfs/fat_file.h195
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos.h408
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_create.c208
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_dir.c483
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_eval.c435
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_file.c485
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_free.c56
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_fsunmount.c71
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_handlers_dir.c36
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_handlers_file.c36
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_init.c60
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_initsupp.c149
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_misc.c1087
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_mknod.c90
-rw-r--r--c/src/exec/libfs/src/dosfs/msdos_node_type.c58
-rw-r--r--c/src/exec/libfs/wrapup/Makefile.am4
-rw-r--r--c/src/libfs/ChangeLog17
-rw-r--r--c/src/libfs/configure.ac3
-rw-r--r--c/src/libfs/src/Makefile.am2
-rw-r--r--c/src/libfs/src/dosfs/.cvsignore6
-rw-r--r--c/src/libfs/src/dosfs/Makefile.am80
-rw-r--r--c/src/libfs/src/dosfs/config.h.in1
-rw-r--r--c/src/libfs/src/dosfs/dosfs.h31
-rw-r--r--c/src/libfs/src/dosfs/fat.c695
-rw-r--r--c/src/libfs/src/dosfs/fat.h489
-rw-r--r--c/src/libfs/src/dosfs/fat_fat_operations.c445
-rw-r--r--c/src/libfs/src/dosfs/fat_fat_operations.h58
-rw-r--r--c/src/libfs/src/dosfs/fat_file.c979
-rw-r--r--c/src/libfs/src/dosfs/fat_file.h195
-rw-r--r--c/src/libfs/src/dosfs/msdos.h408
-rw-r--r--c/src/libfs/src/dosfs/msdos_create.c208
-rw-r--r--c/src/libfs/src/dosfs/msdos_dir.c483
-rw-r--r--c/src/libfs/src/dosfs/msdos_eval.c435
-rw-r--r--c/src/libfs/src/dosfs/msdos_file.c485
-rw-r--r--c/src/libfs/src/dosfs/msdos_free.c56
-rw-r--r--c/src/libfs/src/dosfs/msdos_fsunmount.c71
-rw-r--r--c/src/libfs/src/dosfs/msdos_handlers_dir.c36
-rw-r--r--c/src/libfs/src/dosfs/msdos_handlers_file.c36
-rw-r--r--c/src/libfs/src/dosfs/msdos_init.c60
-rw-r--r--c/src/libfs/src/dosfs/msdos_initsupp.c149
-rw-r--r--c/src/libfs/src/dosfs/msdos_misc.c1087
-rw-r--r--c/src/libfs/src/dosfs/msdos_mknod.c90
-rw-r--r--c/src/libfs/src/dosfs/msdos_node_type.c58
-rw-r--r--c/src/libfs/src/dosfs/stamp-h2.in0
-rw-r--r--c/src/libfs/wrapup/Makefile.am4
-rw-r--r--cpukit/libfs/ChangeLog17
-rw-r--r--cpukit/libfs/configure.ac3
-rw-r--r--cpukit/libfs/src/Makefile.am2
-rw-r--r--cpukit/libfs/src/dosfs/.cvsignore6
-rw-r--r--cpukit/libfs/src/dosfs/Makefile.am80
-rw-r--r--cpukit/libfs/src/dosfs/dosfs.h31
-rw-r--r--cpukit/libfs/src/dosfs/fat.c695
-rw-r--r--cpukit/libfs/src/dosfs/fat.h489
-rw-r--r--cpukit/libfs/src/dosfs/fat_fat_operations.c445
-rw-r--r--cpukit/libfs/src/dosfs/fat_fat_operations.h58
-rw-r--r--cpukit/libfs/src/dosfs/fat_file.c979
-rw-r--r--cpukit/libfs/src/dosfs/fat_file.h195
-rw-r--r--cpukit/libfs/src/dosfs/msdos.h408
-rw-r--r--cpukit/libfs/src/dosfs/msdos_create.c208
-rw-r--r--cpukit/libfs/src/dosfs/msdos_dir.c483
-rw-r--r--cpukit/libfs/src/dosfs/msdos_eval.c435
-rw-r--r--cpukit/libfs/src/dosfs/msdos_file.c485
-rw-r--r--cpukit/libfs/src/dosfs/msdos_free.c56
-rw-r--r--cpukit/libfs/src/dosfs/msdos_fsunmount.c71
-rw-r--r--cpukit/libfs/src/dosfs/msdos_handlers_dir.c36
-rw-r--r--cpukit/libfs/src/dosfs/msdos_handlers_file.c36
-rw-r--r--cpukit/libfs/src/dosfs/msdos_init.c60
-rw-r--r--cpukit/libfs/src/dosfs/msdos_initsupp.c149
-rw-r--r--cpukit/libfs/src/dosfs/msdos_misc.c1087
-rw-r--r--cpukit/libfs/src/dosfs/msdos_mknod.c90
-rw-r--r--cpukit/libfs/src/dosfs/msdos_node_type.c58
-rw-r--r--cpukit/libfs/wrapup/Makefile.am4
83 files changed, 19993 insertions, 6 deletions
diff --git a/c/src/exec/libfs/ChangeLog b/c/src/exec/libfs/ChangeLog
index b4dd8e9f61..4166f2e369 100644
--- a/c/src/exec/libfs/ChangeLog
+++ b/c/src/exec/libfs/ChangeLog
@@ -1,3 +1,20 @@
+2002-02-28 Victor V. Vengerov <vvv@oktet.ru>
+
+ * DOS filesystem including FAT12, FAT16, and FAT32 support submitted.
+ * src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in,
+ src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c,
+ src/dosfs/fat.h, src/dosfs/fat_fat_operations.c,
+ src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c,
+ src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c,
+ src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c,
+ src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c,
+ src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c,
+ src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c,
+ src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c,
+ src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files.
+ * configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to
+ reflect addition.
+
2002-01-07 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* src/imfs/imfs_load_tar.c: Add include <sys/types.h>.
diff --git a/c/src/exec/libfs/configure.ac b/c/src/exec/libfs/configure.ac
index 4e2adeb1b5..7f36fac28e 100644
--- a/c/src/exec/libfs/configure.ac
+++ b/c/src/exec/libfs/configure.ac
@@ -5,6 +5,7 @@
AC_PREREQ(2.52)
AC_INIT
AC_CONFIG_SRCDIR([src/imfs/imfs.h])
+AC_CONFIG_SRCDIR([src/dosfs/dosfs.h])
RTEMS_TOP(../../..)
AC_CONFIG_AUX_DIR(../../..)
@@ -27,11 +28,13 @@ RTEMS_CANONICALIZE_TOOLS
AM_CONDITIONAL(UNIX,test x"$RTEMS_CPU" = x"unix")
AM_CONFIG_HEADER(src/imfs/config.h)
+AM_CONFIG_HEADER(src/dosfs/config.h)
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
src/Makefile
src/imfs/Makefile
+src/dosfs/Makefile
wrapup/Makefile
])
AC_OUTPUT
diff --git a/c/src/exec/libfs/src/Makefile.am b/c/src/exec/libfs/src/Makefile.am
index 126a226126..fcd82899b4 100644
--- a/c/src/exec/libfs/src/Makefile.am
+++ b/c/src/exec/libfs/src/Makefile.am
@@ -4,7 +4,7 @@
AUTOMAKE_OPTIONS = foreign 1.4
-SUBDIRS = imfs
+SUBDIRS = imfs dosfs
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/exec/libfs/src/dosfs/.cvsignore b/c/src/exec/libfs/src/dosfs/.cvsignore
new file mode 100644
index 0000000000..7bb609bf24
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+config.h
+config.h.in
+stamp-h
+stamp-h.in
diff --git a/c/src/exec/libfs/src/dosfs/Makefile.am b/c/src/exec/libfs/src/dosfs/Makefile.am
new file mode 100644
index 0000000000..44c9f4cd2f
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/Makefile.am
@@ -0,0 +1,80 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+INCLUDES = -I.
+
+LIBNAME = libdosfs
+LIB = ${ARCH}/${LIBNAME}.a
+
+FATFS_C_FILES = fat.c fat_fat_operations.c fat_file.c
+
+DOSFS_C_FILES = msdos_create.c msdos_dir.c msdos_eval.c msdos_file.c \
+ msdos_free.c msdos_fsunmount.c msdos_handlers_dir.c \
+ msdos_handlers_file.c msdos_init.c msdos_initsupp.c \
+ msdos_misc.c msdos_mknod.c msdos_node_type.c
+
+
+UNIX_C_FILES = msdos_unixstub.c
+
+EMBEDDED_C_FILES = $(FATFS_C_FILES) $(DOSFS_C_FILES)
+
+COMMON_C_FILES =
+
+if UNIX
+C_FILES = $(COMMON_C_FILES) $(UNIX_C_FILES)
+else
+C_FILES = $(COMMON_C_FILES) $(EMBEDDED_C_FILES)
+endif
+C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
+
+include_HEADERS = fat.h fat_fat_operations.h \
+ fat_file.h msdos.h dosfs.h
+SYS_H_FILES =
+RTEMS_H_FILES =
+noinst_HEADERS =
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+PREINSTALL_FILES = $(PROJECT_INCLUDE) $(PROJECT_INCLUDE)/rtems \
+ $(PROJECT_INCLUDE)/sys $(include_HEADERS:%=$(PROJECT_INCLUDE)/%) \
+ $(RTEMS_H_FILES:%=$(PROJECT_INCLUDE)/rtems/%) \
+ $(SYS_H_FILES:%=$(PROJECT_INCLUDE)/sys/%)
+
+$(PROJECT_INCLUDE):
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/sys:
+ @$(mkinstalldirs) $@
+
+$(PROJECT_INCLUDE)/%.h: %.h
+ $(INSTALL_DATA) $< $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+$(PROJECT_INCLUDE)/sys/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+OBJS = $(C_O_FILES)
+
+#
+# Add local stuff here using +=
+#
+
+AM_CFLAGS += $(LIBC_DEFINES)
+
+all-local: ${ARCH} $(LIB)
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+DOC_FILES =
+
+EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \
+ $(UNIX_C_FILES) $(RTEMS_H_FILES) $(SYS_H_FILES)
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/exec/libfs/src/dosfs/dosfs.h b/c/src/exec/libfs/src/dosfs/dosfs.h
new file mode 100644
index 0000000000..4cea929d4c
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/dosfs.h
@@ -0,0 +1,31 @@
+/*
+ * dosfs.h
+ *
+ * Application interface to MSDOS filesystem.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_DOSFS_H__
+#define __DOSFS_DOSFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+extern rtems_filesystem_operations_table msdos_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_DOSFS_H__ */
diff --git a/c/src/exec/libfs/src/dosfs/fat.c b/c/src/exec/libfs/src/dosfs/fat.c
new file mode 100644
index 0000000000..852c104781
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/fat.c
@@ -0,0 +1,695 @@
+/*
+ * fat.c
+ *
+ * Low-level operations on a volume with FAT filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+
+/* _fat_block_read --
+ * This function reads 'count' bytes from device filesystem is mounted on,
+ * starts at 'start+offset' position where 'start' computed in sectors
+ * and 'offset' is offset inside sector (reading may cross sectors
+ * boundary; in this case assumed we want to read sequential sector(s))
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start - sector num to start read from
+ * offset - offset inside sector 'start'
+ * count - count of bytes to read
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes read on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+_fat_block_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ void *buff
+ )
+{
+ int rc = RC_OK;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ ssize_t cmpltd = 0;
+ unsigned32 blk = start;
+ unsigned32 ofs = offset;
+ bdbuf_buffer *block = NULL;
+ unsigned32 c = 0;
+
+ while (count > 0)
+ {
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ if (rc != RC_OK)
+ return rc;
+
+ c = MIN(count, (fs_info->vol.bps - ofs));
+ memcpy((buff + cmpltd), (block->buffer + ofs), c);
+
+ count -= c;
+ cmpltd += c;
+ blk++;
+ ofs = 0;
+ }
+ return cmpltd;
+}
+
+/* _fat_block_write --
+ * This function write 'count' bytes to device filesystem is mounted on,
+ * starts at 'start+offset' position where 'start' computed in sectors
+ * and 'offset' is offset inside sector (writing may cross sectors
+ * boundary; in this case assumed we want to write sequential sector(s))
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start - sector num to start read from
+ * offset - offset inside sector 'start'
+ * count - count of bytes to write
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+_fat_block_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ const void *buff)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ ssize_t cmpltd = 0;
+ unsigned32 blk = start;
+ unsigned32 ofs = offset;
+ bdbuf_buffer *block = NULL;
+ unsigned32 c = 0;
+
+ while(count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bps - ofs));
+
+ if (c == fs_info->vol.bps)
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
+ else
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ if (rc != RC_OK)
+ return rc;
+
+ memcpy((block->buffer + ofs), (buff + cmpltd), c);
+
+ fat_buf_mark_modified(fs_info);
+
+ count -= c;
+ cmpltd +=c;
+ blk++;
+ ofs = 0;
+ }
+ return cmpltd;
+}
+
+
+
+
+/* fat_cluster_read --
+ * wrapper for reading a whole cluster at once
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to read
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes read on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+fat_cluster_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ void *buff
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 fsec = 0;
+
+ fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
+
+ return _fat_block_read(mt_entry, fsec, 0,
+ fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+}
+
+/* fat_cluster_write --
+ * wrapper for writting a whole cluster at once
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to write
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+fat_cluster_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ const void *buff
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 fsec = 0;
+
+ fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
+
+ return _fat_block_write(mt_entry, fsec, 0,
+ fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+}
+
+/* fat_init_volume_info --
+ * Get inforamtion about volume on which filesystem is mounted on
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ register fat_vol_t *vol = &fs_info->vol;
+ unsigned32 data_secs = 0;
+ char boot_rec[FAT_MAX_BPB_SIZE];
+ char fs_info_sector[FAT_USEFUL_INFO_SIZE];
+ ssize_t ret = 0;
+ int fd;
+ struct stat stat_buf;
+ int i = 0;
+
+ rc = stat(mt_entry->dev, &stat_buf);
+ if (rc == -1)
+ return rc;
+
+ /* rtmes feature: no block devices, all are character devices */
+ if (!S_ISCHR(stat_buf.st_mode))
+ set_errno_and_return_minus_one(ENOTBLK);
+
+ /* check that device is registred as block device and lock it */
+ vol->dd = rtems_disk_lookup(stat_buf.st_dev);
+ if (vol->dd == NULL)
+ set_errno_and_return_minus_one(ENOTBLK);
+
+ vol->dev = stat_buf.st_dev;
+
+ fd = open(mt_entry->dev, O_RDONLY);
+ if (fd == -1)
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ ret = read(fd, (void *)boot_rec, FAT_MAX_BPB_SIZE);
+ if ( ret != FAT_MAX_BPB_SIZE )
+ {
+ close(fd);
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EIO );
+ }
+ close(fd);
+
+ vol->bps = FAT_BR_BYTES_PER_SECTOR(boot_rec);
+
+ if ( (vol->bps != 512) &&
+ (vol->bps != 1024) &&
+ (vol->bps != 2048) &&
+ (vol->bps != 4096))
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+
+ for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
+ i >>= 1, vol->sec_mul++);
+ for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
+ i >>= 1, vol->sec_log2++);
+
+ vol->spc = FAT_BR_SECTORS_PER_CLUSTER(boot_rec);
+ for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
+ i >>= 1, vol->spc_log2++);
+
+ /*
+ * According to M$ White Paper "bytes per cluster" value
+ * greater than 32K is invalid
+ */
+ if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one(EINVAL);
+ }
+
+ for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
+ i >>= 1, vol->bpc_log2++);
+
+ vol->fats = FAT_BR_FAT_NUM(boot_rec);
+ vol->fat_loc = FAT_BR_RESERVED_SECTORS_NUM(boot_rec);
+
+ vol->rdir_entrs = FAT_BR_FILES_PER_ROOT_DIR(boot_rec);
+
+ /* calculate the count of sectors occupied by the root directory */
+ vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
+ vol->bps;
+
+ vol->rdir_size = vol->rdir_secs << vol->sec_log2;
+
+ if ( (FAT_BR_SECTORS_PER_FAT(boot_rec)) != 0)
+ vol->fat_length = FAT_BR_SECTORS_PER_FAT(boot_rec);
+ else
+ vol->fat_length = FAT_BR_SECTORS_PER_FAT32(boot_rec);
+
+ vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
+ vol->rdir_secs;
+
+ /* for FAT12/16 root dir starts at(sector) */
+ vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
+
+ if ( (FAT_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
+ vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM16(boot_rec);
+ else
+ vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM32(boot_rec);
+
+ data_secs = vol->tot_secs - vol->data_fsec;
+
+ vol->data_cls = data_secs / vol->spc;
+
+ /* determine FAT type at least */
+ if ( vol->data_cls < FAT_FAT12_MAX_CLN)
+ {
+ vol->type = FAT_FAT12;
+ vol->mask = FAT_FAT12_MASK;
+ vol->eoc_val = FAT_FAT12_EOC;
+ }
+ else
+ {
+ if ( vol->data_cls < FAT_FAT16_MAX_CLN)
+ {
+ vol->type = FAT_FAT16;
+ vol->mask = FAT_FAT16_MASK;
+ vol->eoc_val = FAT_FAT16_EOC;
+ }
+ else
+ {
+ vol->type = FAT_FAT32;
+ vol->mask = FAT_FAT32_MASK;
+ vol->eoc_val = FAT_FAT32_EOC;
+ }
+ }
+
+ if (vol->type == FAT_FAT32)
+ {
+ vol->rdir_cl = FAT_BR_FAT32_ROOT_CLUSTER(boot_rec);
+
+ vol->mirror = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
+ if (vol->mirror)
+ vol->afat = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
+ else
+ vol->afat = 0;
+
+ vol->info_sec = FAT_BR_FAT32_FS_INFO_SECTOR(boot_rec);
+ if( vol->info_sec == 0 )
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+ else
+ {
+ ret = _fat_block_read(mt_entry, vol->info_sec , 0,
+ FAT_FSI_LEADSIG_SIZE, fs_info_sector);
+ if ( ret < 0 )
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ if (FAT_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
+ FAT_FSINFO_LEAD_SIGNATURE_VALUE)
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+ else
+ {
+ ret = _fat_block_read(mt_entry, vol->info_sec , FAT_FSI_INFO,
+ FAT_USEFUL_INFO_SIZE, fs_info_sector);
+ if ( ret < 0 )
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ vol->free_cls = FAT_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
+ vol->next_cl = FAT_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
+ rc = fat_fat32_update_fsinfo_sector(mt_entry, 0xFFFFFFFF,
+ 0xFFFFFFFF);
+ if ( rc != RC_OK )
+ {
+ rtems_disk_release(vol->dd);
+ return rc;
+ }
+ }
+ }
+ }
+ else
+ {
+ vol->rdir_cl = 0;
+ vol->mirror = 0;
+ vol->afat = 0;
+ vol->free_cls = 0xFFFFFFFF;
+ vol->next_cl = 0xFFFFFFFF;
+ }
+ vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
+
+ /* set up collection of fat-files fd */
+ fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
+ if ( fs_info->vhash == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ _Chain_Initialize_empty(fs_info->vhash + i);
+
+ fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
+ if ( fs_info->rhash == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ _Chain_Initialize_empty(fs_info->rhash + i);
+
+ fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
+ fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
+ fs_info->index = 0;
+ fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
+ if ( fs_info->uino == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ fs_info->sec_buf = (char *)calloc(vol->bps, sizeof(char));
+ if (fs_info->sec_buf == NULL)
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ free(fs_info->uino);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+
+ return RC_OK;
+}
+
+/* fat_shutdown_drive --
+ * Free all allocated resources and synchronize all necessary data
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ int i = 0;
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ rc = fat_fat32_update_fsinfo_sector(mt_entry, fs_info->vol.free_cls,
+ fs_info->vol.next_cl);
+ if ( rc != RC_OK )
+ rc = -1;
+ }
+
+ fat_buf_release(fs_info);
+
+ if (rtems_bdbuf_syncdev(fs_info->vol.dev) != RTEMS_SUCCESSFUL)
+ rc = -1;
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ {
+ Chain_Node *node = NULL;
+ Chain_Control *the_chain = fs_info->vhash + i;
+
+ while ( (node = _Chain_Get(the_chain)) != NULL )
+ free(node);
+ }
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ {
+ Chain_Node *node = NULL;
+ Chain_Control *the_chain = fs_info->rhash + i;
+
+ while ( (node = _Chain_Get(the_chain)) != NULL )
+ free(node);
+ }
+
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+
+ free(fs_info->uino);
+ free(fs_info->sec_buf);
+ rtems_disk_release(fs_info->vol.dd);
+
+ if (rc)
+ errno = EIO;
+ return rc;
+}
+
+/* fat_init_clusters_chain --
+ * Zeroing contents of all clusters in the chain
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start_cluster_num - num of first cluster in the chain
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_init_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start_cln
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = start_cln;
+ char *buf;
+
+ buf = calloc(fs_info->vol.bpc, sizeof(char));
+ if ( buf == NULL )
+ set_errno_and_return_minus_one( EIO );
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ ret = fat_cluster_write(mt_entry, cur_cln, buf);
+ if ( ret == -1 )
+ {
+ free(buf);
+ return -1;
+ }
+
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ {
+ free(buf);
+ return rc;
+ }
+
+ }
+ free(buf);
+ return rc;
+}
+
+#define FAT_UNIQ_INO_BASE 0x0FFFFF00
+
+#define FAT_UNIQ_INO_IS_BUSY(index, arr) \
+ (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
+
+#define FAT_SET_UNIQ_INO_BUSY(index, arr) \
+ ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
+
+#define FAT_SET_UNIQ_INO_FREE(index, arr) \
+ ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
+
+/* fat_get_unique_ino --
+ * Allocate unique ino from unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * unique inode number on success, or 0 if there is no free unique inode
+ * number in the pool
+ *
+ * ATTENTION:
+ * 0 means FAILED !!!
+ *
+ */
+unsigned32
+fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0;
+ rtems_boolean resrc_unsuff = FALSE;
+
+ while (!resrc_unsuff)
+ {
+ for (j = 0; j < fs_info->uino_pool_size; j++)
+ {
+ if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
+ {
+ FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
+ return (fs_info->uino_base + fs_info->index);
+ }
+ fs_info->index++;
+ if (fs_info->index >= fs_info->uino_pool_size)
+ fs_info->index = 0;
+ }
+
+ if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
+ {
+ fs_info->uino_pool_size <<= 1;
+ fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
+ if (fs_info->uino != NULL)
+ fs_info->index = fs_info->uino_pool_size;
+ else
+ resrc_unsuff = TRUE;
+ }
+ else
+ resrc_unsuff = TRUE;
+ }
+ return 0;
+}
+
+/* fat_free_unique_ino --
+ * Return unique ino to unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * ino - inode number to free
+ *
+ * RETURNS:
+ * None
+ */
+void
+fat_free_unique_ino(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
+}
+
+/* fat_ino_is_unique --
+ * Test whether ino is from unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * ino - ino to be tested
+ *
+ * RETURNS:
+ * TRUE if ino is allocated from unique ino pool, FALSE otherwise
+ */
+inline rtems_boolean
+fat_ino_is_unique(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ return (ino >= fs_info->uino_base);
+}
+
+/* fat_fat32_update_fsinfo_sector --
+ * Synchronize fsinfo sector for FAT32 volumes
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * free_count - count of free clusters
+ * next_free - the next free cluster num
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_fat32_update_fsinfo_sector(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 free_count,
+ unsigned32 next_free
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_free_count = 0;
+ unsigned32 le_next_free = 0;
+
+ le_free_count = CT_LE_L(free_count);
+ le_next_free = CT_LE_L(next_free);
+
+ ret1 = _fat_block_write(mt_entry,
+ fs_info->vol.info_sec,
+ FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
+ 4,
+ (char *)(&le_free_count));
+
+ ret2 = _fat_block_write(mt_entry,
+ fs_info->vol.info_sec,
+ FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
+ 4,
+ (char *)(&le_next_free));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+ \ No newline at end of file
diff --git a/c/src/exec/libfs/src/dosfs/fat.h b/c/src/exec/libfs/src/dosfs/fat.h
new file mode 100644
index 0000000000..04a1f0f662
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/fat.h
@@ -0,0 +1,489 @@
+/*
+ * fat.h
+ *
+ * Constants/data structures/prototypes for low-level operations on a volume
+ * with FAT filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#ifndef __DOSFS_FAT_H__
+#define __DOSFS_FAT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/seterr.h>
+
+/* XXX: temporary hack :(( */
+#ifndef set_errno_and_return_minus_one
+#define set_errno_and_return_minus_one rtems_set_errno_and_return_minus_one
+#endif /* set_errno_and_return_minus_one */
+
+#include <rtems/score/cpu.h>
+#include <errno.h>
+#include <rtems/bdbuf.h>
+
+#define DBG1(x) x
+#define DBG2(x) x
+
+#ifndef RC_OK
+#define RC_OK 0x00000000
+#endif
+
+/*
+ * Remember that all FAT file system on disk data structure is
+ * "little endian"!
+ * (derived from linux)
+ */
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ *
+ * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian,
+ * BE = big-endian, c: W = word (16 bits), L = longword (32 bits)
+ */
+
+#if (CPU_BIG_ENDIAN == TRUE)
+# define CF_LE_W(v) CPU_swap_u16(v)
+# define CF_LE_L(v) CPU_swap_u32(v)
+# define CT_LE_W(v) CPU_swap_u16(v)
+# define CT_LE_L(v) CPU_swap_u32(v)
+#else
+# define CF_LE_W(v) (v)
+# define CF_LE_L(v) (v)
+# define CT_LE_W(v) (v)
+# define CT_LE_L(v) (v)
+#endif
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define FAT_HASH_SIZE 2
+#define FAT_HASH_MODULE FAT_HASH_SIZE
+
+
+#define FAT_SECTOR512_SIZE 512 /* sector size (bytes) */
+#define FAT_SECTOR512_BITS 9 /* log2(SECTOR_SIZE) */
+
+/* maximum + 1 number of clusters for FAT12 */
+#define FAT_FAT12_MAX_CLN 4085
+
+/* maximum + 1 number of clusters for FAT16 */
+#define FAT_FAT16_MAX_CLN 65525
+
+#define FAT_FAT12 0x01
+#define FAT_FAT16 0x02
+#define FAT_FAT32 0x04
+
+#define FAT_UNDEFINED_VALUE 0xFFFFFFFF
+
+#define FAT_FAT12_EOC 0x0FFF
+#define FAT_FAT16_EOC 0xFFFF
+#define FAT_FAT32_EOC 0x0FFFFFFF
+
+#define FAT_FAT12_FREE 0x0000
+#define FAT_FAT16_FREE 0x0000
+#define FAT_FAT32_FREE 0x00000000
+
+#define FAT_GENFAT_EOC 0xFFFFFFFF
+#define FAT_GENFAT_FREE 0x00000000
+
+#define FAT_FAT12_SHIFT 0x04
+
+#define FAT_FAT12_MASK 0x00000FFF
+#define FAT_FAT16_MASK 0x0000FFFF
+#define FAT_FAT32_MASK 0x0FFFFFFF
+
+#define FAT_MAX_BPB_SIZE 90
+
+/* size of useful information in FSInfo sector */
+#define FAT_USEFUL_INFO_SIZE 12
+
+#define FAT_VAL8(x, ofs) (unsigned8)(*((unsigned8 *)(x) + (ofs)))
+
+#define FAT_VAL16(x, ofs) \
+ (unsigned16)( (*((unsigned8 *)(x) + (ofs))) | \
+ ((*((unsigned8 *)(x) + (ofs) + 1)) << 8) )
+
+#define FAT_VAL32(x, ofs) \
+ (unsigned32)( (*((unsigned8 *)(x) + (ofs))) | \
+ ((*((unsigned8 *)(x) + (ofs) + 1)) << 8) | \
+ ((*((unsigned8 *)(x) + (ofs) + 2)) << 16) | \
+ ((*((unsigned8 *)(x) + (ofs) + 3)) << 24) )
+
+/* macros to access boot sector fields */
+#define FAT_BR_BYTES_PER_SECTOR(x) FAT_VAL16(x, 11)
+#define FAT_BR_SECTORS_PER_CLUSTER(x) FAT_VAL8(x, 13)
+#define FAT_BR_RESERVED_SECTORS_NUM(x) FAT_VAL16(x, 14)
+#define FAT_BR_FAT_NUM(x) FAT_VAL8(x, 16)
+#define FAT_BR_FILES_PER_ROOT_DIR(x) FAT_VAL16(x, 17)
+#define FAT_BR_TOTAL_SECTORS_NUM16(x) FAT_VAL16(x, 19)
+#define FAT_BR_MEDIA(x) FAT_VAL8(x, 21)
+#define FAT_BR_SECTORS_PER_FAT(x) FAT_VAL16(x, 22)
+#define FAT_BR_TOTAL_SECTORS_NUM32(x) FAT_VAL32(x, 32)
+#define FAT_BR_SECTORS_PER_FAT32(x) FAT_VAL32(x, 36)
+#define FAT_BR_EXT_FLAGS(x) FAT_VAL16(x, 40)
+#define FAT_BR_FAT32_ROOT_CLUSTER(x) FAT_VAL32(x, 44)
+#define FAT_BR_FAT32_FS_INFO_SECTOR(x) FAT_VAL16(x, 48)
+#define FAT_FSINFO_LEAD_SIGNATURE(x) FAT_VAL32(x, 0)
+/*
+ * I read FSInfo sector from offset 484 to access the information, so offsets
+ * of these fields a relative
+ */
+#define FAT_FSINFO_FREE_CLUSTER_COUNT(x) FAT_VAL32(x, 4)
+#define FAT_FSINFO_NEXT_FREE_CLUSTER(x) FAT_VAL32(x, 8)
+
+#define FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET 488
+
+#define FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET 492
+
+#define FAT_RSRVD_CLN 0x02
+
+#define FAT_FSINFO_LEAD_SIGNATURE_VALUE 0x41615252
+
+#define FAT_FSI_LEADSIG_SIZE 0x04
+
+#define FAT_FSI_INFO 484
+
+#define MS_BYTES_PER_CLUSTER_LIMIT 0x8000 /* 32K */
+
+#define FAT_BR_EXT_FLAGS_MIRROR 0x0080
+
+#define FAT_BR_EXT_FLAGS_FAT_NUM 0x000F
+
+
+#define FAT_DIRENTRY_SIZE 32
+
+#define FAT_DIRENTRIES_PER_SEC512 16
+
+/*
+ * Volume descriptor
+ * Description of the volume the FAT filesystem is located on - generally
+ * the fields of the structure corresponde to Boot Sector and BPB Srtucture
+ * (see M$ White Paper) fields
+ */
+typedef struct fat_vol_s
+{
+ unsigned16 bps; /* bytes per sector */
+ unsigned8 sec_log2; /* log2 of bps */
+ unsigned8 sec_mul; /* log2 of 512bts sectors number per sector */
+ unsigned8 spc; /* sectors per cluster */
+ unsigned8 spc_log2; /* log2 of spc */
+ unsigned16 bpc; /* bytes per cluster */
+ unsigned8 bpc_log2; /* log2 of bytes per cluster */
+ unsigned8 fats; /* number of FATs */
+ unsigned8 type; /* FAT type */
+ unsigned32 mask;
+ unsigned32 eoc_val;
+ unsigned16 fat_loc; /* FAT start */
+ unsigned32 fat_length; /* sectors per FAT */
+ unsigned32 rdir_loc; /* root directory start */
+ unsigned16 rdir_entrs; /* files per root directory */
+ unsigned32 rdir_secs; /* sectors per root directory */
+ unsigned32 rdir_size; /* root directory size in bytes */
+ unsigned32 tot_secs; /* total count of sectors */
+ unsigned32 data_fsec; /* first data sector */
+ unsigned32 data_cls; /* count of data clusters */
+ unsigned32 rdir_cl; /* first cluster of the root directory */
+ unsigned16 info_sec; /* FSInfo Sector Structure location */
+ unsigned32 free_cls; /* last known free clusters count */
+ unsigned32 next_cl; /* next free cluster number */
+ unsigned8 mirror; /* mirroring enabla/disable */
+ unsigned32 afat_loc; /* active FAT location */
+ unsigned8 afat; /* the number of active FAT */
+ dev_t dev; /* device ID */
+ disk_device *dd; /* disk device (see libblock) */
+ void *private_data; /* reserved */
+} fat_vol_t;
+
+
+typedef struct fat_cache_s
+{
+ unsigned32 blk_num;
+ rtems_boolean modified;
+ unsigned8 state;
+ bdbuf_buffer *buf;
+} fat_cache_t;
+
+/*
+ * This structure identifies the instance of the filesystem on the FAT
+ * ("fat-file") level.
+ */
+typedef struct fat_fs_info_s
+{
+ fat_vol_t vol; /* volume descriptor */
+ Chain_Control *vhash; /* "vhash" of fat-file descriptors */
+ Chain_Control *rhash; /* "rhash" of fat-file descriptors */
+ char *uino; /* array of unique ino numbers */
+ unsigned32 index;
+ unsigned32 uino_pool_size; /* size */
+ unsigned32 uino_base;
+ fat_cache_t c; /* cache */
+ unsigned8 *sec_buf; /* just placeholder for anything */
+} fat_fs_info_t;
+
+/*
+ * if the name we looking for is file we store not only first data cluster
+ * number, but and cluster number and offset for directory entry for this
+ * name
+ */
+typedef struct fat_auxiliary_s
+{
+ unsigned32 cln;
+ unsigned32 ofs;
+} fat_auxiliary_t;
+
+#define FAT_FAT_OFFSET(fat_type, cln) \
+ ((fat_type) & FAT_FAT12 ? ((cln) + ((cln) >> 1)) : \
+ (fat_type) & FAT_FAT16 ? ((cln) << 1) : \
+ ((cln) << 2))
+
+#define FAT_CLUSTER_IS_ODD(n) ((n) & 0x0001)
+
+#define FAT12_SHIFT 0x4 /* half of a byte */
+
+/* initial size of array of unique ino */
+#define FAT_UINO_POOL_INIT_SIZE 0x100
+
+/* cache support */
+#define FAT_CACHE_EMPTY 0x0
+#define FAT_CACHE_ACTUAL 0x1
+
+#define FAT_OP_TYPE_READ 0x1
+#define FAT_OP_TYPE_GET 0x2
+
+static inline unsigned32
+fat_cluster_num_to_sector_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln
+ )
+{
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ if ( (cln == 0) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)) )
+ return fs_info->vol.rdir_loc;
+
+ return (((cln - FAT_RSRVD_CLN) << fs_info->vol.spc_log2) +
+ fs_info->vol.data_fsec);
+}
+
+static inline unsigned32
+fat_cluster_num_to_sector512_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ if (cln == 1)
+ return 1;
+
+ return (fat_cluster_num_to_sector_num(mt_entry, cln) <<
+ fs_info->vol.sec_mul);
+}
+
+static inline int
+fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type,
+ bdbuf_buffer **buf)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned8 i;
+ rtems_boolean sec_of_fat;
+
+
+ if (fs_info->c.state == FAT_CACHE_EMPTY)
+ {
+ if (op_type == FAT_OP_TYPE_READ)
+ sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
+ else
+ sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.blk_num = blk;
+ fs_info->c.state = FAT_CACHE_ACTUAL;
+ }
+
+ sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
+ (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+
+ if (fs_info->c.blk_num != blk)
+ {
+ if (fs_info->c.modified)
+ {
+ if (sec_of_fat && !fs_info->vol.mirror)
+ memcpy(fs_info->sec_buf, fs_info->c.buf->buffer,
+ fs_info->vol.bps);
+
+ sc = rtems_bdbuf_release_modified(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.modified = 0;
+
+ if (sec_of_fat && !fs_info->vol.mirror)
+ {
+ bdbuf_buffer *b;
+
+ for (i = 1; i < fs_info->vol.fats; i++)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dev,
+ fs_info->c.blk_num +
+ fs_info->vol.fat_length * i,
+ &b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+ }
+ }
+ else
+ {
+ sc = rtems_bdbuf_release(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ }
+ if (op_type == FAT_OP_TYPE_READ)
+ sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
+ else
+ sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.blk_num = blk;
+ }
+ *buf = fs_info->c.buf;
+ return RC_OK;
+}
+
+
+static inline int
+fat_buf_release(fat_fs_info_t *fs_info)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned8 i;
+ rtems_boolean sec_of_fat;
+
+ if (fs_info->c.state == FAT_CACHE_EMPTY)
+ return RC_OK;
+
+ sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
+ (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+
+ if (fs_info->c.modified)
+ {
+ if (sec_of_fat && !fs_info->vol.mirror)
+ memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps);
+
+ sc = rtems_bdbuf_release_modified(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.modified = 0;
+
+ if (sec_of_fat && !fs_info->vol.mirror)
+ {
+ bdbuf_buffer *b;
+
+ for (i = 1; i < fs_info->vol.fats; i++)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dev,
+ fs_info->c.blk_num +
+ fs_info->vol.fat_length * i,
+ &b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+ }
+ }
+ else
+ {
+ sc = rtems_bdbuf_release(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ }
+ fs_info->c.state = FAT_CACHE_EMPTY;
+ return RC_OK;
+}
+
+static inline void
+fat_buf_mark_modified(fat_fs_info_t *fs_info)
+{
+ fs_info->c.modified = TRUE;
+}
+
+
+
+ssize_t
+_fat_block_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ void *buff);
+
+ssize_t
+_fat_block_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ const void *buff);
+
+ssize_t
+fat_cluster_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ void *buff);
+
+ssize_t
+fat_cluster_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ const void *buff);
+
+int
+fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+int
+fat_init_clusters_chain(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start_cln);
+
+unsigned32
+fat_cluster_num_to_sector_num(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln);
+
+int
+fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+
+unsigned32
+fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+rtems_boolean
+fat_ino_is_unique(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino);
+
+void
+fat_free_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino);
+
+int
+fat_fat32_update_fsinfo_sector(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 free_count,
+ unsigned32 next_free
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_H__ */
diff --git a/c/src/exec/libfs/src/dosfs/fat_fat_operations.c b/c/src/exec/libfs/src/dosfs/fat_fat_operations.c
new file mode 100644
index 0000000000..49b2ab70d3
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/fat_fat_operations.c
@@ -0,0 +1,445 @@
+/*
+ * fat_fat_operations.c
+ *
+ * General operations on File Allocation Table
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+
+/* fat_scan_fat_for_free_clusters --
+ * Allocate chain of free clusters from Files Allocation Table
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * chain - the number of the first allocated cluster (first cluster
+ * in the chain)
+ * count - count of clusters to allocate (chain length)
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ *
+ */
+int
+fat_scan_fat_for_free_clusters(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 *chain,
+ unsigned32 count,
+ unsigned32 *cls_added,
+ unsigned32 *last_cl
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cl4find = 2;
+ unsigned32 next_cln = 0;
+ unsigned32 save_cln = 0;
+ unsigned32 data_cls_val = fs_info->vol.data_cls + 2;
+ unsigned32 i = 2;
+
+ *cls_added = 0;
+
+ if (count == 0)
+ return rc;
+
+ if ((fs_info->vol.type & FAT_FAT32) &&
+ (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE))
+ cl4find = fs_info->vol.next_cl;
+
+ /*
+ * fs_info->vol.data_cls is exactly the count of data clusters
+ * starting at cluster 2, so the maximum valid cluster number is
+ * (fs_info->vol.data_cls + 1)
+ */
+ while (i < data_cls_val)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln);
+ if ( rc != RC_OK )
+ {
+ if (*cls_added != 0)
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ return rc;
+ }
+
+ if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)
+ {
+ /*
+ * We are enforced to process allocation of the first free cluster
+ * by separate 'if' statement because otherwise undo function
+ * wouldn't work properly
+ */
+ if (*cls_added == 0)
+ {
+ *chain = cl4find;
+ rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ {
+ /*
+ * this is the first cluster we tried to allocate so no
+ * cleanup activity needed
+ */
+ return rc;
+ }
+ }
+ else
+ {
+ /* set EOC value to new allocated cluster */
+ rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ {
+ /* cleanup activity */
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ return rc;
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
+ if ( rc != RC_OK )
+ {
+ /* cleanup activity */
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ /* trying to save last allocated cluster for future use */
+ fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
+ fat_buf_release(fs_info);
+ return rc;
+ }
+ }
+
+ save_cln = cl4find;
+ (*cls_added)++;
+
+ /* have we satisfied request ? */
+ if (*cls_added == count)
+ {
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = save_cln;
+ if (fs_info->vol.free_cls != 0xFFFFFFFF)
+ fs_info->vol.free_cls -= (*cls_added);
+ }
+ *last_cl = save_cln;
+ fat_buf_release(fs_info);
+ return rc;
+ }
+ }
+ i++;
+ cl4find++;
+ if (cl4find >= data_cls_val)
+ cl4find = 2;
+ }
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = save_cln;
+ if (fs_info->vol.free_cls != 0xFFFFFFFF)
+ fs_info->vol.free_cls -= (*cls_added);
+ }
+ *last_cl = save_cln;
+ fat_buf_release(fs_info);
+ return RC_OK;
+}
+
+/* fat_free_fat_clusters_chain --
+ * Free chain of clusters in Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * chain - number of the first cluster in the chain
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_free_fat_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 chain
+ )
+{
+ int rc = RC_OK, rc1 = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = chain;
+ unsigned32 next_cln = 0;
+ unsigned32 freed_cls_cnt = 0;
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);
+ if ( rc != RC_OK )
+ {
+ if ((fs_info->vol.type & FAT_FAT32) &&
+ (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))
+ fs_info->vol.free_cls += freed_cls_cnt;
+ fat_buf_release(fs_info);
+ return rc;
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);
+ if ( rc != RC_OK )
+ rc1 = rc;
+
+ freed_cls_cnt++;
+ cur_cln = next_cln;
+ }
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = chain;
+ if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
+ fs_info->vol.free_cls += freed_cls_cnt;
+ }
+
+ fat_buf_release(fs_info);
+ if (rc1 != RC_OK)
+ return rc1;
+
+ return RC_OK;
+}
+
+/* fat_get_fat_cluster --
+ * Fetches the contents of the cluster (link to next cluster in the chain)
+ * from Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to fetch the contents from
+ * ret_val - contents of the cluster 'cln' (link to next cluster in
+ * the chain)
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_get_fat_cluster(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 *ret_val
+ )
+{
+ int rc = RC_OK;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ bdbuf_buffer *block0 = NULL;
+ unsigned32 sec = 0;
+ unsigned32 ofs = 0;
+
+ /* sanity check */
+ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
+ set_errno_and_return_minus_one(EIO);
+
+ sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
+ fs_info->vol.afat_loc;
+ ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
+
+ rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ switch ( fs_info->vol.type )
+ {
+ case FAT_FAT12:
+ /*
+ * we are enforced in complex computations for FAT12 to escape CPU
+ * align problems for some architectures
+ */
+ *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;
+ }
+ else
+ {
+ *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;
+ }
+
+ if ( FAT_CLUSTER_IS_ODD(cln) )
+ *ret_val = (*ret_val) >> FAT12_SHIFT;
+ else
+ *ret_val = (*ret_val) & FAT_FAT12_MASK;
+
+ break;
+
+ case FAT_FAT16:
+ *ret_val = *((unsigned16 *)(block0->buffer + ofs));
+ *ret_val = CF_LE_W(*ret_val);
+ break;
+
+ case FAT_FAT32:
+ *ret_val = *((unsigned32 *)(block0->buffer + ofs));
+ *ret_val = CF_LE_L(*ret_val);
+ break;
+
+ default:
+ set_errno_and_return_minus_one(EIO);
+ break;
+ }
+
+ return RC_OK;
+}
+
+/* fat_set_fat_cluster --
+ * Set the contents of the cluster (link to next cluster in the chain)
+ * from Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to set contents to
+ * in_val - value to set
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_set_fat_cluster(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 in_val
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 ofs = 0;
+ unsigned16 fat16_clv = 0;
+ unsigned32 fat32_clv = 0;
+ bdbuf_buffer *block0 = NULL;
+
+ /* sanity check */
+ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
+ set_errno_and_return_minus_one(EIO);
+
+ sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
+ fs_info->vol.afat_loc;
+ ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
+
+ rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ switch ( fs_info->vol.type )
+ {
+ case FAT_FAT12:
+ if ( FAT_CLUSTER_IS_ODD(cln) )
+ {
+ fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) |
+ (unsigned8)(fat16_clv & 0x00FF);
+
+ fat_buf_mark_modified(fs_info);
+
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *((unsigned8 *)(block0->buffer)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+
+ fat_buf_mark_modified(fs_info);
+ }
+ else
+ {
+ *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer + ofs + 1)) =
+ (*((unsigned8 *)(block0->buffer + ofs + 1))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+ }
+ }
+ else
+ {
+ fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));
+
+ *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) |
+ (unsigned8)(fat16_clv & 0x00FF);
+
+ fat_buf_mark_modified(fs_info);
+
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) & 0xF0;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+
+ fat_buf_mark_modified(fs_info);
+ }
+ else
+ {
+ *((unsigned8 *)(block0->buffer + ofs + 1)) =
+ (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;
+
+ *((unsigned8 *)(block0->buffer + ofs+1)) =
+ (*((unsigned8 *)(block0->buffer + ofs+1))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+ }
+ }
+ break;
+
+ case FAT_FAT16:
+ *((unsigned16 *)(block0->buffer + ofs)) =
+ (unsigned16)(CT_LE_W(in_val));
+ fat_buf_mark_modified(fs_info);
+ break;
+
+ case FAT_FAT32:
+ fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
+
+ *((unsigned32 *)(block0->buffer + ofs)) =
+ (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
+
+ *((unsigned32 *)(block0->buffer + ofs)) =
+ fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));
+
+ fat_buf_mark_modified(fs_info);
+ break;
+
+ default:
+ set_errno_and_return_minus_one(EIO);
+ break;
+
+ }
+
+ return RC_OK;
+}
diff --git a/c/src/exec/libfs/src/dosfs/fat_fat_operations.h b/c/src/exec/libfs/src/dosfs/fat_fat_operations.h
new file mode 100644
index 0000000000..59b6a84018
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/fat_fat_operations.h
@@ -0,0 +1,58 @@
+/*
+ * fat_fat_operations.h
+ *
+ * Constants/data structures/prototypes for operations on Files Allocation
+ * Table
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_FAT_FAT_OPERATIONS_H__
+#define __DOSFS_FAT_FAT_OPERATIONS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <rtems/bdbuf.h>
+#include "fat.h"
+
+int
+fat_get_fat_cluster(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 *ret_val);
+
+int
+fat_set_fat_cluster(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 in_val);
+
+int
+fat_scan_fat_for_free_clusters(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 *chain,
+ unsigned32 count,
+ unsigned32 *cls_added,
+ unsigned32 *last_cl
+);
+
+int
+fat_free_fat_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 chain
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_FAT_OPERATIONS_H__ */
diff --git a/c/src/exec/libfs/src/dosfs/fat_file.c b/c/src/exec/libfs/src/dosfs/fat_file.c
new file mode 100644
index 0000000000..4fd8a5024f
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/fat_file.c
@@ -0,0 +1,979 @@
+/*
+ * fat_file.c
+ *
+ * General operations on "fat-file"
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ *
+ */
+
+#include <bsp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+static inline void
+_hash_insert(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el);
+
+static inline void
+_hash_delete(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el);
+
+static inline int
+_hash_search(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ Chain_Control *hash,
+ unsigned32 key1,
+ unsigned32 key2,
+ void **ret
+);
+
+static int
+fat_file_lseek(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 file_cln,
+ unsigned32 *disk_cln
+);
+
+/* fat_file_open --
+ * Open fat-file. Two hash tables are accessed by key
+ * constructed from cluster num and offset of the node (i.e.
+ * files/directories are distinguished by location on the disk).
+ * First, hash table("vhash") consists of fat-file descriptors corresponded
+ * to "valid" files is accessed. Search is made by 2 fields equal to key
+ * constructed. If descriptor is found in the "vhash" - return it.
+ * Otherwise search is made in hash table("rhash") consits of fat-file
+ * descriptors corresponded to "removed-but-still-open" files with the
+ * same keys.
+ * If search failed, new fat-file descriptor is added to "vhash"
+ * with both key fields equal to constructed key. Otherwise new fat-file
+ * descriptor is added to "vhash" with first key field equal to key
+ * constructed and the second equal to an unique (unique among all values
+ * of second key fields) value.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - cluster num of the node
+ * ofs - offset of the node
+ * fat_fd - placeholder for returned fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK and pointer to opened descriptor on success, or -1 if error
+ * occured (errno set appropriately)
+ */
+int
+fat_file_open(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 ofs,
+ fat_file_fd_t **fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *lfat_fd = NULL;
+ unsigned32 key = 0;
+
+ /* construct key */
+ key = fat_construct_key(mt_entry, cln, ofs);
+
+ /* access "valid" hash table */
+ rc = _hash_search(mt_entry, fs_info->vhash, key, 0, (void **)&lfat_fd);
+ if ( rc == RC_OK )
+ {
+ /* return pointer to fat_file_descriptor allocated before */
+ (*fat_fd) = lfat_fd;
+ lfat_fd->links_num++;
+ return rc;
+ }
+
+ /* access "removed-but-still-open" hash table */
+ rc = _hash_search(mt_entry, fs_info->rhash, key, key, (void **)&lfat_fd);
+
+ lfat_fd = (*fat_fd) = (fat_file_fd_t*)malloc(sizeof(fat_file_fd_t));
+ if ( lfat_fd == NULL )
+ set_errno_and_return_minus_one( ENOMEM );
+
+ lfat_fd->links_num = 1;
+ lfat_fd->flags &= ~FAT_FILE_REMOVED;
+ lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+
+ if ( rc != RC_OK )
+ lfat_fd->ino = key;
+ else
+ {
+ lfat_fd->ino = fat_get_unique_ino(mt_entry);
+
+ if ( lfat_fd->ino == 0 )
+ {
+ free((*fat_fd));
+ /*
+ * XXX: kernel resource is unsufficient, but not the memory,
+ * but there is no suitable errno :(
+ */
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ }
+ _hash_insert(fs_info->vhash, key, lfat_fd->ino, lfat_fd);
+
+
+ /*
+ * other fields of fat-file descriptor will be initialized on upper
+ * level
+ */
+
+ return RC_OK;
+}
+
+
+/* fat_file_reopen --
+ * Increment by 1 number of links
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK
+ */
+int
+fat_file_reopen(fat_file_fd_t *fat_fd)
+{
+ fat_fd->links_num++;
+ return RC_OK;
+}
+
+/* fat_file_close --
+ * Close fat-file. If count of links to fat-file
+ * descriptor is greater than 1 (i.e. somebody esle holds pointer
+ * to this descriptor) just decrement it. Otherwise
+ * do the following. If this descriptor corresponded to removed fat-file
+ * then free clusters contained fat-file data, delete descriptor from
+ * "rhash" table and free memory allocated by descriptor. If descriptor
+ * correspondes to non-removed fat-file and 'ino' field has value from
+ * unique inode numbers pool then set count of links to descriptor to zero
+ * and leave it in hash, otherwise delete descriptor from "vhash" and free
+ * memory allocated by the descriptor
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_close(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 key = 0;
+
+ /*
+ * if links_num field of fat-file descriptor is greater than 1
+ * decrement the count of links and return
+ */
+ if (fat_fd->links_num > 1)
+ {
+ fat_fd->links_num--;
+ return rc;
+ }
+
+ key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs);
+
+ if (fat_fd->flags & FAT_FILE_REMOVED)
+ {
+ rc = fat_file_truncate(mt_entry, fat_fd, 0);
+ if ( rc != RC_OK )
+ return rc;
+
+ _hash_delete(fs_info->rhash, key, fat_fd->ino, fat_fd);
+
+ if ( fat_ino_is_unique(mt_entry, fat_fd->ino) )
+ fat_free_unique_ino(mt_entry, fat_fd->ino);
+
+ free(fat_fd);
+ }
+ else
+ {
+ if (fat_ino_is_unique(mt_entry, fat_fd->ino))
+ {
+ fat_fd->links_num = 0;
+ }
+ else
+ {
+ _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
+ free(fat_fd);
+ }
+ }
+ return rc;
+}
+
+/* fat_file_read --
+ * Read 'count' bytes from 'start' position from fat-file. This
+ * interface hides the architecture of fat-file, represents it as
+ * linear file
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * start - offset in fat-file (in bytes) to read from
+ * count - count of bytes to read
+ * buf - buffer provided by user
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno
+ * set appropriately)
+ */
+ssize_t
+fat_file_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cmpltd = 0;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 save_cln = 0;
+ unsigned32 ofs = 0;
+ unsigned32 save_ofs;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+ unsigned32 c = 0;
+
+ /* it couldn't be removed - otherwise cache update will be broken */
+ if (count == 0)
+ return cmpltd;
+
+ /*
+ * >= because start is offset and computed from 0 and file_size
+ * computed from 1
+ */
+ if ( start >= fat_fd->fat_file_size )
+ return FAT_EOF;
+
+ if ((count > fat_fd->fat_file_size) ||
+ (start > fat_fd->fat_file_size - count))
+ count = fat_fd->fat_file_size - start;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
+ sec += (start >> fs_info->vol.sec_log2);
+ byte = start & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_read(mt_entry, sec, byte, count, buf);
+ if ( ret < 0 )
+ return -1;
+
+ return ret;
+ }
+
+ cl_start = start >> fs_info->vol.bpc_log2;
+ save_ofs = ofs = start & (fs_info->vol.bpc - 1);
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ while (count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bpc - ofs));
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ sec += (ofs >> fs_info->vol.sec_log2);
+ byte = ofs & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_read(mt_entry, sec, byte, c, buf + cmpltd);
+ if ( ret < 0 )
+ return -1;
+
+ count -= c;
+ cmpltd += c;
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ ofs = 0;
+ }
+
+ /* update cache */
+ /* XXX: check this - I'm not sure :( */
+ fat_fd->map.file_cln = cl_start +
+ ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
+ fat_fd->map.disk_cln = save_cln;
+
+ return cmpltd;
+}
+
+/* fat_file_write --
+ * Write 'count' bytes of data from user supplied buffer to fat-file
+ * starting at offset 'start'. This interface hides the architecture
+ * of fat-file, represents it as linear file
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * start - offset(in bytes) to write from
+ * count - count
+ * buf - buffer provided by user
+ *
+ * RETURNS:
+ * number of bytes actually written to the file on success, or -1 if
+ * error occured (errno set appropriately)
+ */
+ssize_t
+fat_file_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf
+ )
+{
+ int rc = 0;
+ ssize_t ret = 0;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cmpltd = 0;
+ unsigned32 cur_cln = 0;
+ unsigned32 save_cln;
+ unsigned32 cl_start = 0;
+ unsigned32 ofs = 0;
+ unsigned32 save_ofs;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+ unsigned32 c = 0;
+
+ if ( count == 0 )
+ return cmpltd;
+
+ if ( start > fat_fd->fat_file_size )
+ set_errno_and_return_minus_one( EIO );
+
+ if ((count > fat_fd->size_limit) ||
+ (start > fat_fd->size_limit - count))
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_extend(mt_entry, fat_fd, start + count, &c);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * check whether there was enough room on device to locate
+ * file of 'start + count' bytes
+ */
+ if (c != (start + count))
+ count = c - start;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
+ sec += (start >> fs_info->vol.sec_log2);
+ byte = start & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_write(mt_entry, sec, byte, count, buf);
+ if ( ret < 0 )
+ return -1;
+
+ return ret;
+ }
+
+ cl_start = start >> fs_info->vol.bpc_log2;
+ save_ofs = ofs = start & (fs_info->vol.bpc - 1);
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ while (count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bpc - ofs));
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ sec += (ofs >> fs_info->vol.sec_log2);
+ byte = ofs & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_write(mt_entry, sec, byte, c, buf + cmpltd);
+ if ( ret < 0 )
+ return -1;
+
+ count -= c;
+ cmpltd += c;
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ ofs = 0;
+ }
+
+ /* update cache */
+ /* XXX: check this - I'm not sure :( */
+ fat_fd->map.file_cln = cl_start +
+ ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
+ fat_fd->map.disk_cln = save_cln;
+
+ return cmpltd;
+}
+
+/* fat_file_extend --
+ * Extend fat-file. If new length less than current fat-file size -
+ * do nothing. Otherwise calculate necessary count of clusters to add,
+ * allocate it and add new clusters chain to the end of
+ * existing clusters chain.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * new_length - new length
+ * a_length - placeholder for result - actual new length of file
+ *
+ * RETURNS:
+ * RC_OK and new length of file on success, or -1 if error occured (errno
+ * set appropriately)
+ */
+int
+fat_file_extend(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length,
+ unsigned32 *a_length
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 chain = 0;
+ unsigned32 bytes2add = 0;
+ unsigned32 cls2add = 0;
+ unsigned32 old_last_cl;
+ unsigned32 last_cl = 0;
+ unsigned32 bytes_remain = 0;
+ unsigned32 cls_added;
+
+ *a_length = new_length;
+
+ if (new_length <= fat_fd->fat_file_size)
+ return RC_OK;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ set_errno_and_return_minus_one( ENOSPC );
+
+ bytes_remain = (fs_info->vol.bpc -
+ (fat_fd->fat_file_size & (fs_info->vol.bpc - 1))) &
+ (fs_info->vol.bpc - 1);
+
+ bytes2add = new_length - fat_fd->fat_file_size;
+
+ if (bytes2add > bytes_remain)
+ bytes2add -= bytes_remain;
+ else
+ bytes2add = 0;
+
+ /*
+ * if in last cluster allocated for the file there is enough room to
+ * handle extention (hence we don't need to add even one cluster to the
+ * file ) - return
+ */
+ if (bytes2add == 0)
+ return RC_OK;
+
+ cls2add = ((bytes2add - 1) >> fs_info->vol.bpc_log2) + 1;
+
+ rc = fat_scan_fat_for_free_clusters(mt_entry, &chain, cls2add,
+ &cls_added, &last_cl);
+
+ /* this means that low level I/O error occured */
+ if (rc != RC_OK)
+ return rc;
+
+ /* this means that no space left on device */
+ if ((cls_added == 0) && (bytes_remain == 0))
+ set_errno_and_return_minus_one(ENOSPC);
+
+ /* check wether we satisfied request for 'cls2add' clusters */
+ if (cls2add != cls_added)
+ *a_length = new_length -
+ ((cls2add - cls_added - 1) << fs_info->vol.bpc_log2) -
+ (bytes2add & (fs_info->vol.bpc - 1));
+
+ /* add new chain to the end of existed */
+ if ( fat_fd->fat_file_size == 0 )
+ {
+ fat_fd->map.disk_cln = fat_fd->cln = chain;
+ fat_fd->map.file_cln = 0;
+ }
+ else
+ {
+ if (fat_fd->map.last_cln != FAT_UNDEFINED_VALUE)
+ {
+ old_last_cl = fat_fd->map.last_cln;
+ }
+ else
+ {
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ (fat_fd->fat_file_size - 1), &old_last_cl);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, old_last_cl, chain);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ fat_buf_release(fs_info);
+ }
+
+ /* update number of the last cluster of the file if it changed */
+ if (cls_added != 0)
+ {
+ fat_fd->map.last_cln = last_cl;
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ {
+ rc = fat_init_clusters_chain(mt_entry, chain);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ }
+ }
+
+ return RC_OK;
+}
+
+/* fat_file_truncate --
+ * Truncate fat-file. If new length greater than current fat-file size -
+ * do nothing. Otherwise find first cluster to free and free all clusters
+ * in the chain starting from this cluster.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * new_length - new length
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_truncate(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 new_last_cln = FAT_UNDEFINED_VALUE;
+
+
+ if ( new_length >= fat_fd->fat_file_size )
+ return rc;
+
+ assert(fat_fd->fat_file_size);
+
+ cl_start = (new_length + fs_info->vol.bpc - 1) >> fs_info->vol.bpc_log2;
+
+ if ((cl_start << fs_info->vol.bpc_log2) >= fat_fd->fat_file_size)
+ return RC_OK;
+
+ if (cl_start != 0)
+ {
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start - 1, &new_last_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ }
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ rc = fat_free_fat_clusters_chain(mt_entry, cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ if (cl_start != 0)
+ {
+ rc = fat_set_fat_cluster(mt_entry, new_last_cln, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ return rc;
+ fat_fd->map.file_cln = cl_start - 1;
+ fat_fd->map.disk_cln = new_last_cln;
+ fat_fd->map.last_cln = new_last_cln;
+ }
+ return RC_OK;
+}
+
+/* fat_file_ioctl --
+ * F_CLU_NUM:
+ * make mapping between serial number of the cluster in fat-file and
+ * its real number on the volume
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ * mt_entry - mount table entry
+ * cmd - command
+ * ...
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured and errno set appropriately
+ */
+int
+fat_file_ioctl(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ int cmd,
+ ...)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 pos = 0;
+ unsigned32 *ret;
+ va_list ap;
+
+ va_start(ap, cmd);
+
+ switch (cmd)
+ {
+ case F_CLU_NUM:
+ pos = va_arg(ap, int);
+ ret = va_arg(ap, int *);
+
+ /* sanity check */
+ if ( pos >= fat_fd->fat_file_size )
+ set_errno_and_return_minus_one( EIO );
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ /* cluster 0 (zero) reserved for root dir */
+ *ret = 0;
+ return RC_OK;
+ }
+
+ cl_start = pos >> fs_info->vol.bpc_log2;
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ *ret = cur_cln;
+ break;
+
+ default:
+ errno = EINVAL;
+ rc = -1;
+ break;
+ }
+ return rc;
+}
+
+/* fat_file_mark_removed --
+ * Remove the fat-file descriptor from "valid" hash table, insert it
+ * into "removed-but-still-open" hash table and set up "removed" bit.
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * None
+ */
+void
+fat_file_mark_removed(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 key = 0;
+
+ key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs);
+
+ _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
+
+ _hash_insert(fs_info->rhash, key, fat_fd->ino, fat_fd);
+
+ fat_fd->flags |= FAT_FILE_REMOVED;
+}
+
+/* fat_file_datasync --
+ * Synchronize fat-file - flush all buffered data to the media.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured and errno set appropriately
+ */
+int
+fat_file_datasync(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = fat_fd->cln;
+ bdbuf_buffer *block = NULL;
+ unsigned32 sec = 0;
+ unsigned32 i = 0;
+
+ if (fat_fd->fat_file_size == 0)
+ return RC_OK;
+
+ /*
+ * we can use only one bdbuf :( and we also know that cache is useless
+ * for sync operation, so don't use it
+ */
+ rc = fat_buf_release(fs_info);
+ if (rc != RC_OK)
+ return rc;
+
+ /* for each cluster of the file ... */
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ /* for each sector in cluster ... */
+ for ( i = 0; i < fs_info->vol.spc; i++ )
+ {
+ /* ... sync it */
+ sc = rtems_bdbuf_read(fs_info->vol.dev, (sec + i), &block);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ sc = rtems_bdbuf_sync(block);
+ if ( sc != RTEMS_SUCCESSFUL )
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+ }
+ return rc;
+}
+
+/* fat_file_size --
+ * Calculate fat-file size - fat-file is nothing that clusters chain, so
+ * go through all clusters in the chain and count it. Only
+ * special case is root directory for FAT12/16 volumes.
+ * This function is used only for directories which are fat-files with
+ * non-zero length, hence 'fat_fd->cln' always contains valid data.
+ * Calculated size is stored in 'fat_file_size' field of fat-file
+ * descriptor.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = fat_fd->cln;
+ unsigned32 save_cln = 0;
+
+ /* Have we requested root dir size for FAT12/16? */
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ fat_fd->fat_file_size = fs_info->vol.rdir_size;
+ return rc;
+ }
+
+ fat_fd->fat_file_size = 0;
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ fat_fd->fat_file_size += fs_info->vol.bpc;
+ }
+ fat_fd->map.last_cln = save_cln;
+ return rc;
+}
+
+/* hash support routines */
+
+/* _hash_insert --
+ * Insert elemnt into hash based on key 'key1'
+ *
+ * PARAMETERS:
+ * hash - hash element will be inserted into
+ * key1 - key on which insertion is based on
+ * key2 - not used during insertion
+ * el - element to insert
+ *
+ * RETURNS:
+ * None
+ */
+static inline void
+_hash_insert(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el)
+{
+ _Chain_Append((hash) + ((key1) % FAT_HASH_MODULE), &(el)->link);
+}
+
+
+/* _hash_delete --
+ * Remove element from hash
+ *
+ * PARAMETERS:
+ * hash - hash element will be removed from
+ * key1 - not used
+ * key2 - not used
+ * el - element to delete
+ *
+ * RETURNS:
+ * None
+ */
+static inline void
+_hash_delete(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el)
+{
+ _Chain_Extract(&(el)->link);
+}
+
+/* _hash_search --
+ * Search element in hash. If both keys match pointer to found element
+ * is returned
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * hash - hash element will be removed from
+ * key1 - search key
+ * key2 - search key
+ * ret - placeholder for result
+ *
+ * RETURNS:
+ * 0 and pointer to found element on success, -1 otherwise
+ */
+static inline int
+_hash_search(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ Chain_Control *hash,
+ unsigned32 key1,
+ unsigned32 key2,
+ void **ret
+ )
+{
+ unsigned32 mod = (key1) % FAT_HASH_MODULE;
+ Chain_Node *the_node = ((Chain_Control *)((hash) + mod))->first;
+
+ for ( ; !_Chain_Is_tail((hash) + mod, the_node) ; )
+ {
+ fat_file_fd_t *ffd = (fat_file_fd_t *)the_node;
+ unsigned32 ck =
+ fat_construct_key(mt_entry, ffd->info_cln, ffd->info_ofs);
+
+ if ( (key1) == ck)
+ {
+ if ( ((key2) == 0) || ((key2) == ffd->ino) )
+ {
+ *ret = (void *)the_node;
+ return 0;
+ }
+ }
+ the_node = the_node->next;
+ }
+ return -1;
+}
+
+static int
+fat_file_lseek(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 file_cln,
+ unsigned32 *disk_cln
+ )
+{
+ int rc = RC_OK;
+/*
+ assert(fat_fd->fat_file_size);
+ */
+ if (file_cln == fat_fd->map.file_cln)
+ *disk_cln = fat_fd->map.disk_cln;
+ else
+ {
+ unsigned32 cur_cln;
+ unsigned32 count;
+ unsigned32 i;
+
+ if (file_cln > fat_fd->map.file_cln)
+ {
+ cur_cln = fat_fd->map.disk_cln;
+ count = file_cln - fat_fd->map.file_cln;
+ }
+ else
+ {
+ cur_cln = fat_fd->cln;
+ count = file_cln;
+ }
+
+ /* skip over the clusters */
+ for (i = 0; i < count; i++)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+ }
+
+ /* update cache */
+ fat_fd->map.file_cln = file_cln;
+ fat_fd->map.disk_cln = cur_cln;
+
+ *disk_cln = cur_cln;
+ }
+ return RC_OK;
+}
diff --git a/c/src/exec/libfs/src/dosfs/fat_file.h b/c/src/exec/libfs/src/dosfs/fat_file.h
new file mode 100644
index 0000000000..2821a27cf7
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/fat_file.h
@@ -0,0 +1,195 @@
+/*
+ * fat_file.h
+ *
+ * Constants/data structures/prototypes for operations on "fat-file"
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_FAT_FILE_H__
+#define __DOSFS_FAT_FILE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <time.h>
+
+/* "fat-file" representation
+ *
+ * the idea is: fat-file is nothing but a cluster chain, any open fat-file is
+ * represented in system by fat-file descriptor and has well-known
+ * file interface:
+ *
+ * fat_file_open()
+ * fat_file_close()
+ * fat_file_read()
+ * fat_file_write()
+ *
+ * Such interface hides the architecture of fat-file and represents it like
+ * linear file
+ */
+
+typedef rtems_filesystem_node_types_t fat_file_type_t;
+
+#define FAT_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define FAT_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+typedef struct fat_file_map_s
+{
+ unsigned32 file_cln;
+ unsigned32 disk_cln;
+ unsigned32 last_cln;
+} fat_file_map_t;
+/*
+ * descriptor of a fat-file
+ *
+ * To each particular clusters chain
+ */
+typedef struct fat_file_fd_s
+{
+ Chain_Node link; /*
+ * fat-file descriptors organized into hash;
+ * collision lists are handled via link
+ * field
+ */
+ unsigned32 links_num; /*
+ * the number of fat_file_open call on
+ * this fat-file
+ */
+ unsigned32 ino; /* inode, file serial number :)))) */
+ fat_file_type_t fat_file_type;
+ unsigned32 size_limit;
+ unsigned32 fat_file_size; /* length */
+ unsigned32 info_cln;
+ unsigned32 cln;
+ unsigned16 info_ofs;
+ unsigned char first_char;
+ unsigned8 flags;
+ fat_file_map_t map;
+ time_t mtime;
+
+} fat_file_fd_t;
+
+
+#define FAT_FILE_REMOVED 0x01
+
+#define FAT_FILE_IS_REMOVED(p)\
+ (((p)->flags & FAT_FILE_REMOVED) ? 1 : 0)
+
+/* ioctl macros */
+#define F_CLU_NUM 0x01
+
+/*
+ * Each file and directory on a MSDOS volume is unique identified by it
+ * location, i.e. location of it 32 Bytes Directory Entry Structure. We can
+ * distinguish them by cluster number it locates on and offset inside this
+ * cluster. But root directory on any volumes (FAT12/16/32) has no 32 Bytes
+ * Directory Entry Structure corresponded to it. So we assume 32 Bytes
+ * Directory Entry Structure of root directory locates at cluster 1 (invalid
+ * cluaster number) and offset 0
+ */
+#define FAT_ROOTDIR_CLUSTER_NUM 0x01
+
+#define FAT_FD_OF_ROOT_DIR(fat_fd) \
+ ((fat_fd->info_cln == FAT_ROOTDIR_CLUSTER_NUM ) && \
+ (fat_fd->info_ofs == 0))
+
+#define FAT_EOF 0x00
+
+/* fat_construct_key --
+ * Construct key for hash access: convert (cluster num, offset) to
+ * (sector512 num, new offset) and than construct key as
+ * key = (sector512 num) << 4 | (new offset)
+ *
+ * PARAMETERS:
+ * cl - cluster number
+ * ofs - offset inside cluster 'cl'
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * constructed key
+ */
+static inline unsigned32
+fat_construct_key(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs)
+{
+ return ( ((fat_cluster_num_to_sector512_num(mt_entry, cl) +
+ (ofs >> FAT_SECTOR512_BITS)) << 4) +
+ ((ofs >> 5) & (FAT_DIRENTRIES_PER_SEC512 - 1)) );
+}
+
+/* Prototypes for "fat-file" operations */
+int
+fat_file_open(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 ofs,
+ fat_file_fd_t **fat_fd);
+
+int
+fat_file_reopen(fat_file_fd_t *fat_fd);
+
+int
+fat_file_close(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+ssize_t
+fat_file_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf);
+
+ssize_t
+fat_file_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf);
+
+int
+fat_file_extend(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length,
+ unsigned32 *a_length);
+
+int
+fat_file_truncate(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length);
+
+int
+fat_file_datasync(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+
+int
+fat_file_ioctl(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ int cmd,
+ ...);
+
+int
+fat_file_size(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+void
+fat_file_mark_removed(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_FILE_H__ */
diff --git a/c/src/exec/libfs/src/dosfs/msdos.h b/c/src/exec/libfs/src/dosfs/msdos.h
new file mode 100644
index 0000000000..a9216b1ed3
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos.h
@@ -0,0 +1,408 @@
+/*
+ * msdos.h
+ *
+ * The MSDOS filesystem constants/data structures/prototypes
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_MSDOS_H__
+#define __DOSFS_MSDOS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_file.h"
+
+#ifndef RC_OK
+#define RC_OK 0x00000000
+#endif
+
+#define MSDOS_NAME_NOT_FOUND_ERR 0xDD000001
+
+/*
+ * This structure identifies the instance of the filesystem on the MSDOS
+ * level.
+ */
+typedef struct msdos_fs_info_s
+{
+ fat_fs_info_t fat; /*
+ * volume
+ * description
+ */
+ rtems_filesystem_file_handlers_r *directory_handlers; /*
+ * a set of routines
+ * that handles the
+ * nodes of directory
+ * type
+ */
+ rtems_filesystem_file_handlers_r *file_handlers; /*
+ * a set of routines
+ * that handles the
+ * nodes of file
+ * type
+ */
+ rtems_id vol_sema; /*
+ * semaphore
+ * associated with
+ * the volume
+ */
+ unsigned8 *cl_buf; /*
+ * just placeholder
+ * for anything
+ */
+} msdos_fs_info_t;
+
+/* a set of routines that handle the nodes which are directories */
+extern rtems_filesystem_file_handlers_r msdos_dir_handlers;
+
+/* a set of routines that handle the nodes which are files */
+extern rtems_filesystem_file_handlers_r msdos_file_handlers;
+
+/* Volume semaphore timeout value */
+#define MSDOS_VOLUME_SEMAPHORE_TIMEOUT 100
+
+/* Node types */
+#define MSDOS_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define MSDOS_REGULAR_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+typedef rtems_filesystem_node_types_t msdos_node_type_t;
+
+/*
+ * Macros for fetching fields from 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE 32 /* 32 bytes */
+
+#define MSDOS_DIR_NAME(x) (unsigned8 *)((x) + 0)
+#define MSDOS_DIR_ATTR(x) (unsigned8 *)((x) + 11)
+#define MSDOS_DIR_NT_RES(x) (unsigned8 *)((x) + 12)
+#define MSDOS_DIR_CRT_TIME_TENTH(x) (unsigned8 *)((x) + 13)
+#define MSDOS_DIR_CRT_TIME(x) (unsigned16 *)((x) + 14)
+#define MSDOS_DIR_CRT_DATE(x) (unsigned16 *)((x) + 16)
+#define MSDOS_DIR_LAST_ACCESS_DATE(x) (unsigned16 *)((x) + 18)
+#define MSDOS_DIR_FIRST_CLUSTER_HI(x) (unsigned16 *)((x) + 20)
+#define MSDOS_DIR_WRITE_TIME(x) (unsigned16 *)((x) + 22)
+#define MSDOS_DIR_WRITE_DATE(x) (unsigned16 *)((x) + 24)
+#define MSDOS_DIR_FIRST_CLUSTER_LOW(x) (unsigned16 *)((x) + 26)
+#define MSDOS_DIR_FILE_SIZE(x) (unsigned32 *)((x) + 28)
+
+#define MSDOS_EXTRACT_CLUSTER_NUM(p) \
+ (unsigned32)( (CF_LE_W(*MSDOS_DIR_FIRST_CLUSTER_LOW(p))) | \
+ ((CF_LE_W((*MSDOS_DIR_FIRST_CLUSTER_HI(p))))<<16) )
+
+/*
+ * Fields offset in 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_FILE_SIZE_OFFSET 28
+#define MSDOS_FILE_NAME_OFFSET 0
+#define MSDOS_FIRST_CLUSTER_HI_OFFSET 20
+#define MSDOS_FIRST_CLUSTER_LOW_OFFSET 26
+#define MSDOS_FILE_WDATE_OFFSET 24
+#define MSDOS_FILE_WTIME_OFFSET 22
+
+/*
+ * Possible values of DIR_Attr field of 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_ATTR_READ_ONLY 0x01
+#define MSDOS_ATTR_HIDDEN 0x02
+#define MSDOS_ATTR_SYSTEM 0x04
+#define MSDOS_ATTR_VOLUME_ID 0x08
+#define MSDOS_ATTR_DIRECTORY 0x10
+#define MSDOS_ATTR_ARCHIVE 0x20
+
+/*
+ * Possible values of DIR_Name[0] field of 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_THIS_DIR_ENTRY_EMPTY 0xE5
+#define MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY 0x00
+
+
+/*
+ * Macros for names parsing and formatting
+ */
+#define msdos_is_valid_name_char(_ch) (1)
+#define msdos_is_separator(_ch) rtems_filesystem_is_separator(_ch)
+
+#define MSDOS_SHORT_NAME_LEN 11 /* 11 characters */
+#define MSDOS_NAME_MAX MSDOS_SHORT_NAME_LEN
+#define MSDOS_NAME_MAX_WITH_DOT (MSDOS_NAME_MAX + 1)
+
+#define MSDOS_DOT_NAME ". " /* ".", padded to MSDOS_NAME chars */
+#define MSDOS_DOTDOT_NAME ".. " /* "..", padded to MSDOS_NAME chars */
+
+typedef enum msdos_token_types_e
+{
+ MSDOS_NO_MORE_PATH,
+ MSDOS_CURRENT_DIR,
+ MSDOS_UP_DIR,
+ MSDOS_NAME,
+ MSDOS_INVALID_TOKEN
+} msdos_token_types_t;
+
+/* Others macros */
+#define MSDOS_RES_NT_VALUE 0x00
+#define MSDOS_INIT_DIR_SIZE 0x00
+
+/* "dot" entry offset in a directory */
+#define MSDOS_DOT_DIR_ENTRY_OFFSET 0x00 /* first entry in directory */
+
+/* "dotdot" entry offset in a directory */
+#define MSDOS_DOTDOT_DIR_ENTRY_OFFSET 0x20 /* second entry in directory */
+
+/* 'p' should be char* */
+#define DOT_NODE_P(p) ((char *)(p))
+#define DOTDOT_NODE_P(p) ((char *)((p) + MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE))
+
+/* Size limits for files and directories (see M$ White Paper) */
+#define MSDOS_MAX_DIR_LENGHT 0x200000 /* 2,097,152 bytes */
+#define MSDOS_MAX_FILE_SIZE 0xFFFFFFFF /* 4 Gb */
+
+/*
+ * The number of 32 bytes long FAT Directory Entry
+ * Structures per 512 bytes sector
+ */
+#define MSDOS_DPS512_NUM 16
+
+/* Prototypes */
+int
+msdos_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+int
+msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+int
+msdos_eval_path(const char *pathname, /* IN */
+ int flags, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */);
+
+int
+msdos_eval4make(const char *path, /* IN */
+ rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
+ const char **name /* OUT */);
+
+int
+msdos_unlink(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_free_node_info(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+rtems_filesystem_node_types_t
+msdos_node_type(rtems_filesystem_location_info_t *pathloc);
+
+int
+msdos_mknod(const char *path, /* IN */
+ mode_t mode, /* IN */
+ dev_t dev, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */);
+
+int
+msdos_utime(rtems_filesystem_location_info_t *pathloc, /* IN */
+ time_t actime, /* IN */
+ time_t modtime /* IN */);
+
+int
+msdos_initialize_support(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry,
+ rtems_filesystem_operations_table *op_table,
+ rtems_filesystem_file_handlers_r *file_handlers,
+ rtems_filesystem_file_handlers_r *directory_handlers
+);
+
+int
+msdos_file_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+
+int
+msdos_file_close(rtems_libio_t *iop /* IN */);
+
+ssize_t
+msdos_file_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+ssize_t
+msdos_file_write(
+ rtems_libio_t *iop, /* IN */
+ const void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+int
+msdos_file_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+
+int
+msdos_file_stat(rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */);
+
+int
+msdos_file_ftruncate(
+ rtems_libio_t *iop, /* IN */
+ off_t length /* IN */
+);
+
+int
+msdos_file_sync(rtems_libio_t *iop);
+
+int
+msdos_file_datasync(rtems_libio_t *iop);
+
+int
+msdos_file_ioctl(
+ rtems_libio_t *iop, /* IN */
+ unsigned32 command, /* IN */
+ void *buffer /* IN */
+);
+
+int
+msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_dir_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+
+int
+msdos_dir_close(rtems_libio_t *iop /* IN */);
+
+ssize_t
+msdos_dir_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+int
+msdos_dir_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+
+int
+msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_dir_sync(rtems_libio_t *iop);
+
+int
+msdos_dir_stat(
+ rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */
+);
+
+int
+msdos_creat_node(rtems_filesystem_location_info_t *parent_loc,
+ msdos_node_type_t type,
+ char *name,
+ mode_t mode);
+
+/* Misc prototypes */
+msdos_token_types_t msdos_get_token(const char *path,
+ char *token,
+ int *token_len);
+
+int
+msdos_find_name(rtems_filesystem_location_info_t *parent_loc,
+ char *name);
+
+int
+msdos_get_name_node(rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry);
+
+int
+msdos_dir_info_remove(rtems_filesystem_location_info_t *pathloc);
+
+void
+msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date);
+
+unsigned int
+msdos_date_dos2unix(unsigned short time_val, unsigned short date);
+
+int
+msdos_set_first_cluster_num(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+int
+msdos_set_file_size(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+int
+msdos_set_first_char4file_name(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char first_char);
+
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+);
+
+
+int
+msdos_dir_is_empty(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val);
+
+int
+msdos_find_name_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry);
+
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+);
+
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_MSDOS_H__ */
diff --git a/c/src/exec/libfs/src/dosfs/msdos_create.c b/c/src/exec/libfs/src/dosfs/msdos_create.c
new file mode 100644
index 0000000000..4b4c7001ca
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_create.c
@@ -0,0 +1,208 @@
+/*
+ * Routine to create a new MSDOS filesystem node
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ *
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtems/libio_.h>
+#include <time.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_creat_node --
+ * Create a new node. If a new node is file, FAT 32 Bytes Directory
+ * Entry Structure (see M$ White Paper) is initialized, free space is
+ * found in parent directory and structure is written to the disk.
+ * In case of directory, all above steps present and also new cluster
+ * is allocated for a new directory and dot and dotdot nodes are created
+ * in alloceted cluster.
+ *
+ * PARAMETERS:
+ * parent_loc - parent (directory we are going to create node in)
+ * type - new node type (file or directory)
+ * name - new node name
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ *
+ */
+int
+msdos_creat_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ msdos_node_type_t type,
+ char *name,
+ mode_t mode
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *parent_fat_fd = parent_loc->node_access;
+ fat_file_fd_t *fat_fd = NULL;
+ time_t time_ret = 0;
+ unsigned16 time_val = 0;
+ unsigned16 date = 0;
+ fat_auxiliary_t aux;
+ unsigned char new_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
+
+ memset(new_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
+
+ /* set up name */
+ strncpy(MSDOS_DIR_NAME(new_node), name, MSDOS_NAME_MAX);
+
+ /* fill reserved field */
+ *MSDOS_DIR_NT_RES(new_node) = MSDOS_RES_NT_VALUE;
+
+ /* set up last write date and time */
+ time_ret = time(NULL);
+ if ( time_ret == -1 )
+ return -1;
+
+ msdos_date_unix2dos(time_ret, &time_val, &date);
+ *MSDOS_DIR_WRITE_TIME(new_node) = CT_LE_W(time_val);
+ *MSDOS_DIR_WRITE_DATE(new_node) = CT_LE_W(date);
+
+ /* initialize directory/file size */
+ *MSDOS_DIR_FILE_SIZE(new_node) = MSDOS_INIT_DIR_SIZE;
+
+ if (type == MSDOS_DIRECTORY)
+ *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_DIRECTORY;
+ else
+ *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE;
+
+ /*
+ * find free space in the parent directory and write new initialized
+ * FAT 32 Bytes Directory Entry Structure (see M$ White Paper)
+ * to the disk
+ */
+ rc = msdos_get_name_node(parent_loc, NULL, &aux, new_node);
+ if ( rc != RC_OK )
+ return rc;
+
+ /*
+ * if we create a new file we are done, if directory there are more steps
+ * to do
+ */
+ if (type == MSDOS_DIRECTORY)
+ {
+ /* open new directory as fat-file */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ /*
+ * we opened fat-file for node we just created, so initialize fat-file
+ * descritor
+ */
+ fat_fd->info_cln = aux.cln;
+ fat_fd->info_ofs = aux.ofs;
+ fat_fd->fat_file_size = 0;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ /*
+ * dot and dotdot entries are identical to new node except the
+ * names
+ */
+ memcpy(DOT_NODE_P(dot_dotdot), new_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memcpy(DOTDOT_NODE_P(dot_dotdot), new_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
+ MSDOS_NAME_MAX);
+ memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
+ MSDOS_NAME_MAX);
+
+ /* set up cluster num for dotdot entry */
+ /*
+ * here we can ommit FAT32 condition because for all FAT types dirs
+ * right under root dir should contain 0 in dotdot entry but for
+ * FAT12/16 parent_fat_fd->cluster_num always contains such value
+ */
+ if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
+ (fs_info->fat.vol.type & FAT_FAT32))
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ }
+ else
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)((parent_fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
+ }
+
+ /*
+ * write dot and dotdot entries to new fat-file: currently fat-file
+ * correspondes to a new node is zero length, so it will be extended
+ * by one cluster and entries will be written
+ */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
+ dot_dotdot);
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* increment fat-file size by cluster size */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* set up cluster num for dot entry */
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)((fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)(((fat_fd->cln) & 0xFFFF0000) >> 16));
+
+ /* rewrite dot entry */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ DOT_NODE_P(dot_dotdot));
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* write first cluster num of a new directory to disk */
+ rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto error;
+
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ }
+ return RC_OK;
+
+error:
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+
+err:
+ /* mark 32bytes structure on the disk as free */
+ msdos_set_first_char4file_name(parent_loc->mt_entry, aux.cln, aux.ofs,
+ 0xE5);
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_dir.c b/c/src/exec/libfs/src/dosfs/msdos_dir.c
new file mode 100644
index 0000000000..93449cd2fb
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_dir.c
@@ -0,0 +1,483 @@
+/*
+ * MSDOS directory handlers implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <rtems/libio_.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_dir_open --
+ * Open fat-file which correspondes to the directory being opened and
+ * set offset field of file control block to zero.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * pathname - name
+ * flag - flags
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK, if directory opened successfully, or -1 if error occured (errno
+ * set apropriately)
+ */
+int
+msdos_dir_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
+ unsigned32 mode)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ iop->offset = 0;
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_close --
+ * Close fat-file which correspondes to the directory being closed
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK, if directory closed successfully, or -1 if error occured (errno
+ * set apropriately.
+ */
+int
+msdos_dir_close(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_read --
+ * 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.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - buffer provided by user
+ * count - count of bytes to read
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+ssize_t
+msdos_dir_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ fat_file_fd_t *tmp_fat_fd = NULL;
+ struct dirent tmp_dirent;
+ unsigned32 start = 0;
+ ssize_t ret = 0;
+ unsigned32 cmpltd = 0;
+ unsigned32 j = 0, i = 0;
+ unsigned32 bts2rd = 0;
+ unsigned32 cur_cln = 0;
+
+ /*
+ * cast start and count - protect against using sizes that are not exact
+ * multiples of the -dirent- size. These could result in unexpected
+ * results
+ */
+ start = iop->offset / sizeof(struct dirent);
+ count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
+
+ /*
+ * optimization: we know that root directory for FAT12/16 volumes is
+ * sequential set of sectors and any cluster is sequential set of sectors
+ * too, so read such set of sectors is quick operation for low-level IO
+ * layer.
+ */
+ bts2rd = (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) ?
+ fat_fd->fat_file_size :
+ fs_info->fat.vol.bpc;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ while (count > 0)
+ {
+ /*
+ * fat-file is already opened by open call, so read it
+ * Always read directory fat-file from the beggining because of MSDOS
+ * directories feature :( - we should count elements currently
+ * present in the directory because there may be holes :)
+ */
+ ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, (j * bts2rd),
+ bts2rd, fs_info->cl_buf);
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EIO);
+ }
+
+ for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return cmpltd;
+ }
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY)
+ continue;
+
+ /*
+ * skip active entries until get the entry to start from
+ */
+ if (start)
+ {
+ start--;
+ continue;
+ }
+
+ /*
+ * Move the entry to the return buffer
+ *
+ * unfortunately there is no method to extract ino except to
+ * open fat-file descriptor :( ... so, open it
+ */
+
+ /* get number of cluster we are working with */
+ rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &cur_cln);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = fat_file_open(iop->pathinfo.mt_entry, cur_cln, i,
+ &tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ tmp_fat_fd->info_cln = cur_cln;
+ tmp_fat_fd->info_ofs = i;
+
+ /* fill in dirent structure */
+ /* XXX: from what and in what d_off should be computed ?! */
+ tmp_dirent.d_off = start + cmpltd;
+ tmp_dirent.d_reclen = sizeof(struct dirent);
+ tmp_dirent.d_ino = tmp_fat_fd->ino;
+ tmp_dirent.d_namlen = MSDOS_SHORT_NAME_LEN;
+ memcpy(tmp_dirent.d_name, MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_SHORT_NAME_LEN);
+
+ /* d_name is null-terminated */
+ tmp_dirent.d_name[MSDOS_SHORT_NAME_LEN] = 0;
+ memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
+
+ iop->offset = iop->offset + sizeof(struct dirent);
+ cmpltd += (sizeof(struct dirent));
+ count -= (sizeof(struct dirent));
+
+ /* inode number extracted, close fat-file */
+ rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (count <= 0)
+ break;
+ }
+ j++;
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return cmpltd;
+}
+
+/* msdos_dir_write --
+ * no write for directory
+ */
+
+/* msdos_dir_lseek --
+ *
+ * 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.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * offset - offset
+ * whence - predefine directive
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+int
+msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence)
+{
+ switch (whence)
+ {
+ case SEEK_SET:
+ case SEEK_CUR:
+ break;
+ /*
+ * Movement past the end of the directory via lseek is not a
+ * permitted operation
+ */
+ case SEEK_END:
+ default:
+ set_errno_and_return_minus_one( EINVAL );
+ break;
+ }
+ return RC_OK;
+}
+
+/* msdos_dir_stat --
+ *
+ * This routine will obtain the following information concerning the current
+ * directory:
+ * st_dev device id
+ * st_ino node serial number :)
+ * st_mode mode extracted from the node
+ * st_size total size in bytes
+ * st_blksize blocksize for filesystem I/O
+ * st_blocks number of blocks allocated
+ * stat_mtime time of last modification
+ *
+ * PARAMETERS:
+ * loc - this directory
+ * buf - stat buffer provided by user
+ *
+ * RETURNS:
+ * RC_OK and filled stat buffer on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+int
+msdos_dir_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+ )
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ buf->st_dev = fs_info->fat.vol.dev;
+ buf->st_ino = fat_fd->ino;
+ buf->st_mode = S_IFDIR;
+ buf->st_rdev = 0ll;
+ buf->st_size = fat_fd->fat_file_size;
+ buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
+ buf->st_blksize = fs_info->fat.vol.bps;
+ buf->st_mtime = fat_fd->mtime;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_truncate --
+ * No truncate for directory.
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ */
+
+/* msdos_dir_sync --
+ * The following routine does a syncronization on a MSDOS directory node.
+ * DIR_WrtTime, DIR_WrtDate and DIR_fileSize fields of 32 Bytes Directory
+ * Entry Structure(see M$ White Paper) should not be updated for
+ * directories, so only call to corresponding fat-file routine.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ */
+int
+msdos_dir_sync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_dir_rmnod --
+ * Remove directory node.
+ *
+ * Check that this directory node is not opened as fat-file, is empty and
+ * not filesystem root node. If all this conditions met then delete.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ */
+int
+msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = pathloc->node_access;
+ rtems_boolean is_empty = FALSE;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /*
+ * We deny attemp to delete open directory (if directory is current
+ * directory we assume it is open one)
+ */
+ if (fat_fd->links_num > 1)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EBUSY);
+ }
+
+ /*
+ * You cannot remove a node that still has children
+ */
+ rc = msdos_dir_is_empty(pathloc->mt_entry, fat_fd, &is_empty);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (!is_empty)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(ENOTEMPTY);
+ }
+
+ /*
+ * You cannot remove the file system root node.
+ */
+ if (pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EBUSY);
+ }
+
+ /*
+ * You cannot remove a mountpoint.
+ * not used - mount() not implemenetd yet.
+ */
+
+ /* mark file removed */
+ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
+ fat_fd->info_ofs,
+ MSDOS_THIS_DIR_ENTRY_EMPTY);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ fat_file_mark_removed(pathloc->mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_eval.c b/c/src/exec/libfs/src/dosfs/msdos_eval.c
new file mode 100644
index 0000000000..3eba0e63e8
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_eval.c
@@ -0,0 +1,435 @@
+/*
+ * MSDOS evaluation routines
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_set_handlers --
+ * Set handlers for the node with specified type(i.e. handlers for file
+ * or directory).
+ *
+ * PARAMETERS:
+ * loc - node description
+ *
+ * RETURNS:
+ * None
+ */
+static void
+msdos_set_handlers(rtems_filesystem_location_info_t *loc)
+{
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ loc->handlers = fs_info->directory_handlers;
+ else
+ loc->handlers = fs_info->file_handlers;
+}
+
+/* msdos_eval_path --
+ *
+ * The following routine evaluate path for a node that wishes to be
+ * accessed. Structure 'pathloc' is returned with a pointer to the
+ * node to be accessed.
+ *
+ * PARAMETERS:
+ * pathname - path for evaluation
+ * flags - flags
+ * pathloc - node description (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK and filled pathloc on success, or -1 if error occured
+ * (errno set appropriately)
+ *
+ */
+int
+msdos_eval_path(
+ const char *pathname,
+ int flags,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ int i = 0;
+ int len = 0;
+ msdos_token_types_t type = MSDOS_CURRENT_DIR;
+ char token[MSDOS_NAME_MAX + 1];
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN))
+ {
+ type = msdos_get_token(&pathname[i], token, &len);
+ i += len;
+
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalpath_h)(&(pathname[i-len]),
+ flags, pathloc);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ /*
+ * Always return the root node.
+ *
+ * If we are at a node that is a mount point. Set loc to the
+ * new fs root node and let let the mounted filesystem set the handlers.
+ *
+ * NOTE: The behavior of stat() on a mount point appears to be
+ * questionable.
+ * NOTE: MSDOS filesystem currently doesn't support mount functionality ->
+ * action not implemented
+ */
+ fat_fd = pathloc->node_access;
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_eval4make --
+ * The following routine evaluate path for a new node to be created.
+ * 'pathloc' is returned with a pointer to the parent of the new node.
+ * 'name' is returned with a pointer to the first character in the
+ * new node name. The parent node is verified to be a directory.
+ *
+ * PARAMETERS:
+ * path - path for evaluation
+ * pathloc - IN/OUT (start point for evaluation/parent directory for
+ * creation)
+ * name - new node name
+ *
+ * RETURNS:
+ * RC_OK, filled pathloc for parent directory and name of new node on
+ * success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_eval4make(
+ const char *path,
+ rtems_filesystem_location_info_t *pathloc,
+ const char **name
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ msdos_token_types_t type;
+ int i = 0;
+ int len;
+ char token[ MSDOS_NAME_MAX + 1 ];
+ rtems_boolean done = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while (!done)
+ {
+ type = msdos_get_token(&path[i], token, &len);
+ i += len;
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalformake_h)(&path[i-len],
+ pathloc, name);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc)
+ {
+ if (rc != MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ else
+ done = TRUE;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ errno = EEXIST;
+ rc = -1;
+ goto error;
+ break;
+
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ *name = &path[i - len];
+
+ /*
+ * We have evaluated the path as far as we can.
+ * Verify there is not any invalid stuff at the end of the name.
+ */
+ for( ; path[i] != '\0'; i++)
+ {
+ if (!msdos_is_separator(path[i]))
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ }
+
+ fat_fd = pathloc->node_access;
+
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_file.c b/c/src/exec/libfs/src/dosfs/msdos_file.c
new file mode 100644
index 0000000000..da36827338
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_file.c
@@ -0,0 +1,485 @@
+/*
+ * MSDOS file handlers implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_file_open --
+ * Open fat-file which correspondes to the file
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * pathname - name
+ * flag - flags
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK, if file opened successfully, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+msdos_file_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
+ unsigned32 mode)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (iop->flags & LIBIO_FLAGS_APPEND)
+ iop->offset = fat_fd->fat_file_size;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_close --
+ * Close fat-file which correspondes to the file. If fat-file descriptor
+ * which correspondes to the file is not marked "removed", synchronize
+ * size, first cluster number, write time and date fields of the file.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK, if file closed successfully, or -1 if error occured (errno set
+ * appropriately)
+ */
+int
+msdos_file_close(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /*
+ * if fat-file descriptor is not marked as "removed", synchronize
+ * size, first cluster number, write time and date fields of the file
+ */
+ if (!FAT_FILE_IS_REMOVED(fat_fd))
+ {
+ rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ }
+
+ rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_file_read --
+ * This routine read from file pointed to by file control block into
+ * the specified data buffer provided by user
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - buffer provided by user
+ * count - the number of bytes to read
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno set
+ * appropriately)
+ */
+ssize_t
+msdos_file_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
+{
+ ssize_t ret = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
+ buffer);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return ret;
+}
+
+/* msdos_file_write --
+ * This routine writes the specified data buffer into the file pointed to
+ * by file control block.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - data to write
+ * count - count of bytes to write
+ *
+ * RETURNS:
+ * the number of bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+msdos_file_write(rtems_libio_t *iop,const void *buffer, unsigned32 count)
+{
+ ssize_t ret = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ ret = fat_file_write(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
+ buffer);
+ if (ret < 0)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return -1;
+ }
+
+ /*
+ * update file size in both fat-file descriptor and file control block if
+ * file was extended
+ */
+ if (iop->offset + ret > fat_fd->fat_file_size)
+ fat_fd->fat_file_size = iop->offset + ret;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return ret;
+}
+
+/* msdos_file_lseek --
+ * Process lseek call to the file: extend file if lseek is up to the end
+ * of the file.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * offset - new offset
+ * whence - predefine directive
+ *
+ * RETURNS:
+ * new offset on success, or -1 if error occured (errno set
+ * appropriately).
+ */
+int
+msdos_file_lseek(rtems_libio_t *iop, off_t offset, int whence)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ unsigned32 real_size = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_extend(iop->pathinfo.mt_entry, fat_fd, iop->offset,
+ &real_size);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (real_size > fat_fd->fat_file_size)
+ fat_fd->fat_file_size = iop->offset = real_size;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return iop->offset;
+}
+
+/* msdos_file_stat --
+ *
+ * PARAMETERS:
+ * loc - node description
+ * buf - stat buffer provided by user
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+ )
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ buf->st_dev = fs_info->fat.vol.dev;
+ buf->st_ino = fat_fd->ino;
+ buf->st_mode = S_IFREG;
+ buf->st_rdev = 0ll;
+ buf->st_size = fat_fd->fat_file_size;
+ buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
+ buf->st_blksize = fs_info->fat.vol.bps;
+ buf->st_mtime = fat_fd->mtime;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_ftruncate --
+ * Truncate the file (if new length is greater then current do nothing).
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * length - new length
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ */
+int
+msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ if (length >= fat_fd->fat_file_size)
+ return RC_OK;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ /*
+ * fat_file_truncate do nothing if new length >= fat-file size, so update
+ * file size only if length < fat-file size
+ */
+ if (length < fat_fd->fat_file_size)
+ iop->size = fat_fd->fat_file_size = length;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_sync --
+ * Synchronize file - synchronize file data and if file is not removed
+ * synchronize file metadata.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_sync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* synchronize file data */
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ /*
+ * if fat-file descriptor is not marked "removed" - synchronize file
+ * metadata
+ */
+ if (!FAT_FILE_IS_REMOVED(fat_fd))
+ {
+ rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_datasync --
+ * Synchronize file - synchronize only file data (metadata is letf intact).
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_datasync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* synchronize file data */
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+
+/* msdos_file_ioctl --
+ *
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * ...
+ *
+ * RETURNS:
+ *
+ */
+int
+msdos_file_ioctl(rtems_libio_t *iop,unsigned32 command, void *buffer)
+{
+ int rc = RC_OK;
+
+ return rc;
+}
+
+/* msdos_file_rmnod --
+ * Remove node associated with a file - set up first name character to
+ * predefined value(and write it to the disk), and mark fat-file which
+ * correspondes to the file as "removed"
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = pathloc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* mark file removed */
+ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
+ fat_fd->info_ofs,
+ MSDOS_THIS_DIR_ENTRY_EMPTY);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ fat_file_mark_removed(pathloc->mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_free.c b/c/src/exec/libfs/src/dosfs/msdos_free.c
new file mode 100644
index 0000000000..c0d5938dbb
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_free.c
@@ -0,0 +1,56 @@
+/*
+ * Free node handler implementation for the filesystem
+ * operations table.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <errno.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_free_node_info --
+ * Call fat-file close routine.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 code if error occured
+ *
+ */
+int
+msdos_free_node_info(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_close(pathloc->mt_entry, pathloc->node_access);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_fsunmount.c b/c/src/exec/libfs/src/dosfs/msdos_fsunmount.c
new file mode 100644
index 0000000000..9072a2fad5
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_fsunmount.c
@@ -0,0 +1,71 @@
+/*
+ * MSDOS shut down handler implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_shut_down --
+ * Shut down MSDOS filesystem - free all allocated resources (don't
+ * return if deallocation of some resource failed - free as much as
+ * possible).
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = temp_mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = temp_mt_entry->mt_fs_root.node_access;
+
+ /* close fat-file which correspondes to root directory */
+ if (fat_file_close(temp_mt_entry, fat_fd) != RC_OK)
+ {
+ /* no return - try to free as much as possible */
+ rc = -1;
+ }
+
+ if (fat_shutdown_drive(temp_mt_entry) != RC_OK)
+ {
+ /* no return - try to free as much as possible */
+ rc = -1;
+ }
+
+ rtems_semaphore_delete(fs_info->vol_sema);
+ free(fs_info->cl_buf);
+ free(temp_mt_entry->fs_info);
+
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_handlers_dir.c b/c/src/exec/libfs/src/dosfs/msdos_handlers_dir.c
new file mode 100644
index 0000000000..e14d892add
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_handlers_dir.c
@@ -0,0 +1,36 @@
+/*
+ * Directory Handlers Table for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio.h>
+#include "msdos.h"
+
+rtems_filesystem_file_handlers_r msdos_dir_handlers = {
+ msdos_dir_open,
+ msdos_dir_close,
+ msdos_dir_read,
+ NULL, /* msdos_dir_write */
+ NULL, /* msdos_dir_ioctl */
+ msdos_dir_lseek,
+ msdos_dir_stat,
+ NULL,
+ NULL, /* msdos_dir_ftruncate */
+ NULL,
+ msdos_dir_sync,
+ msdos_dir_sync,
+ NULL, /* msdos_dir_fcntl */
+ msdos_dir_rmnod
+};
diff --git a/c/src/exec/libfs/src/dosfs/msdos_handlers_file.c b/c/src/exec/libfs/src/dosfs/msdos_handlers_file.c
new file mode 100644
index 0000000000..ae627066de
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_handlers_file.c
@@ -0,0 +1,36 @@
+/*
+ * File Operations Table for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio.h>
+#include "msdos.h"
+
+rtems_filesystem_file_handlers_r msdos_file_handlers = {
+ msdos_file_open,
+ msdos_file_close,
+ msdos_file_read,
+ msdos_file_write,
+ msdos_file_ioctl,
+ msdos_file_lseek,
+ msdos_file_stat,
+ NULL,
+ msdos_file_ftruncate,
+ NULL,
+ msdos_file_sync,
+ msdos_file_datasync,
+ NULL, /* msdos_file_fcntl */
+ msdos_file_rmnod
+};
diff --git a/c/src/exec/libfs/src/dosfs/msdos_init.c b/c/src/exec/libfs/src/dosfs/msdos_init.c
new file mode 100644
index 0000000000..2d5bf6c9e0
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_init.c
@@ -0,0 +1,60 @@
+/*
+ * Init routine for MSDOS
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio_.h>
+#include "msdos.h"
+
+rtems_filesystem_operations_table msdos_ops = {
+ msdos_eval_path,
+ msdos_eval4make,
+ NULL, /* msdos_link */
+ msdos_file_rmnod,
+ msdos_node_type,
+ msdos_mknod,
+ NULL, /* msdos_chown */
+ msdos_free_node_info,
+ NULL,
+ msdos_initialize,
+ NULL,
+ msdos_shut_down, /* msdos_shut_down */
+ NULL, /* msdos_utime */
+ NULL,
+ NULL,
+ NULL
+};
+
+/* msdos_initialize --
+ * MSDOS filesystem initialization
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
+{
+ int rc = RC_OK;
+
+ rc = msdos_initialize_support(temp_mt_entry,
+ &msdos_ops,
+ &msdos_file_handlers,
+ &msdos_dir_handlers);
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_initsupp.c b/c/src/exec/libfs/src/dosfs/msdos_initsupp.c
new file mode 100644
index 0000000000..eee8a6f9b2
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_initsupp.c
@@ -0,0 +1,149 @@
+/*
+ * MSDOS Initialization support routine implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_initialize_support --
+ * MSDOS filesystem initialization
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ * op_table - filesystem operations table
+ * file_handlers - file operations table
+ * directory_handlers - directory operations table
+ *
+ * RETURNS:
+ * RC_OK and filled temp_mt_entry on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_initialize_support(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry,
+ rtems_filesystem_operations_table *op_table,
+ rtems_filesystem_file_handlers_r *file_handlers,
+ rtems_filesystem_file_handlers_r *directory_handlers
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = NULL;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned32 cl_buf_size;
+
+ fs_info = (msdos_fs_info_t *)calloc(1, sizeof(msdos_fs_info_t));
+ if (!fs_info)
+ set_errno_and_return_minus_one(ENOMEM);
+
+ temp_mt_entry->fs_info = fs_info;
+
+ rc = fat_init_volume_info(temp_mt_entry);
+ if (rc != RC_OK)
+ {
+ free(fs_info);
+ return rc;
+ }
+
+ fs_info->file_handlers = file_handlers;
+ fs_info->directory_handlers = directory_handlers;
+
+ /*
+ * open fat-file which correspondes to root directory
+ * (so inode number 0x00000010 is always used for root directory)
+ */
+ rc = fat_file_open(temp_mt_entry, FAT_ROOTDIR_CLUSTER_NUM, 0, &fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ return rc;
+ }
+
+ /* again: unfortunately "fat-file" is just almost fat file :( */
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+ fat_fd->info_cln = FAT_ROOTDIR_CLUSTER_NUM;
+ fat_fd->info_ofs = 0;
+ fat_fd->cln = fs_info->fat.vol.rdir_cl;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ /* if we have FAT12/16 */
+ if ( fat_fd->cln == 0 )
+ {
+ fat_fd->fat_file_size = fs_info->fat.vol.rdir_size;
+ cl_buf_size = (fs_info->fat.vol.bpc > fs_info->fat.vol.rdir_size) ?
+ fs_info->fat.vol.bpc :
+ fs_info->fat.vol.rdir_size;
+ }
+ else
+ {
+ rc = fat_file_size(temp_mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ return rc;
+ }
+ cl_buf_size = fs_info->fat.vol.bpc;
+ }
+
+ fs_info->cl_buf = (char *)calloc(cl_buf_size, sizeof(char));
+ if (fs_info->cl_buf == NULL)
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_semaphore_create(3,
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO,
+ RTEMS_INHERIT_PRIORITY,
+ &fs_info->vol_sema);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info->cl_buf);
+ free(fs_info);
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ temp_mt_entry->mt_fs_root.node_access = fat_fd;
+ temp_mt_entry->mt_fs_root.handlers = directory_handlers;
+ temp_mt_entry->mt_fs_root.ops = op_table;
+
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_misc.c b/c/src/exec/libfs/src/dosfs/msdos_misc.c
new file mode 100644
index 0000000000..fe2779f7a8
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_misc.c
@@ -0,0 +1,1087 @@
+/*
+ * Miscellaneous routines implementation for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* This copied from Linux */
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+#undef CONFIG_ATARI
+
+/* MS-DOS "device special files" */
+static const char *reserved_names[] = {
+#ifndef CONFIG_ATARI /* GEMDOS is less stupid */
+ "CON ","PRN ","NUL ","AUX ",
+ "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
+ "COM1 ","COM2 ","COM3 ","COM4 ",
+#endif
+ NULL };
+
+static char bad_chars[] = "*?<>|\"";
+#ifdef CONFIG_ATARI
+/* GEMDOS is less restrictive */
+static char bad_if_strict[] = " ";
+#else
+static char bad_if_strict[] = "+=,; ";
+#endif
+
+/* The following three functions copied from Linux */
+/*
+ * Formats an MS-DOS file name. Rejects invalid names
+ *
+ * conv is relaxed/normal/strict, name is proposed name,
+ * len is the length of the proposed name, res is the result name,
+ * dotsOK is if hidden files get dots.
+ */
+int
+msdos_format_name(char conv, const char *name, int len, char *res,
+ char dotsOK)
+{
+ char *walk;
+ const char **reserved;
+ unsigned char c;
+ int space;
+ if (name[0] == '.') { /* dotfile because . and .. already done */
+ if (!dotsOK) return -EINVAL;
+ /* Get rid of dot - test for it elsewhere */
+ name++; len--;
+ }
+#ifndef CONFIG_ATARI
+ space = 1; /* disallow names that _really_ start with a dot */
+#else
+ space = 0; /* GEMDOS does not care */
+#endif
+ c = 0;
+ for (walk = res; len && walk-res < 8; walk++) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
+/* 0xE5 is legal as a first character, but we must substitute 0x05 */
+/* because 0xE5 marks deleted files. Yes, DOS really does this. */
+/* It seems that Microsoft hacked DOS to support non-US characters */
+/* after the 0xE5 character was already in use to mark deleted files. */
+ if((res==walk) && (c==0xE5)) c=0x05;
+ if (c == '.') break;
+ space = (c == ' ');
+ *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len && c != '.') {
+ c = *name++;
+ len--;
+ if (c != '.') return -EINVAL;
+ }
+ while (c != '.' && len--) c = *name++;
+ if (c == '.') {
+ while (walk-res < 8) *walk++ = ' ';
+ while (len > 0 && walk-res < MSDOS_NAME_MAX) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c))
+ return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\')
+ return -EINVAL;
+ if (c == '.') {
+ if (conv == 's')
+ return -EINVAL;
+ break;
+ }
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ space = c == ' ';
+ *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len) return -EINVAL;
+ }
+ while (walk-res < MSDOS_NAME_MAX) *walk++ = ' ';
+ for (reserved = reserved_names; *reserved; reserved++)
+ if (!strncmp(res,*reserved,8)) return -EINVAL;
+ return 0;
+}
+
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70) */
+unsigned int
+msdos_date_dos2unix(unsigned short time_val,unsigned short date)
+{
+ int month,year,secs;
+
+ month = ((date >> 5) & 15)-1;
+ year = date >> 9;
+ secs = (time_val & 31)*2+60*((time_val >> 5) & 63)+
+ (time_val >> 11)*3600+86400*
+ ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
+ month < 2 ? 1 : 0)+3653);
+ /* days since 1.1.70 plus 80's leap day */
+
+ return secs;
+}
+
+
+/* Convert linear UNIX date to a MS-DOS time/date pair */
+void msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date)
+{
+ int day,year,nl_day,month;
+
+ *time_val = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
+ (((unix_date/3600) % 24) << 11);
+ day = unix_date/86400-3652;
+ year = day/365;
+ if ((year+3)/4+365*year > day) year--;
+ day -= (year+3)/4+365*year;
+ if (day == 59 && !(year & 3)) {
+ nl_day = day;
+ month = 2;
+ }
+ else {
+ nl_day = (year & 3) || day <= 59 ? day : day-1;
+ for (month = 0; month < 12; month++)
+ if (day_n[month] > nl_day) break;
+ }
+ *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+}
+
+
+/* msdos_get_token --
+ * Routine to get a token (name or separator) from the path.
+ *
+ * PARAMETERS:
+ * path - path to get token from
+ * ret_token - returned token
+ * token_len - length of returned token
+ *
+ * RETURNS:
+ * token type, token and token length
+ *
+ */
+msdos_token_types_t
+msdos_get_token(const char *path, char *ret_token, int *token_len)
+{
+ int rc = RC_OK;
+ register int i = 0;
+ msdos_token_types_t type = MSDOS_NAME;
+ char token[MSDOS_NAME_MAX_WITH_DOT+1];
+ register char c;
+
+ /*
+ * Copy a name into token. (Remember NULL is a token.)
+ */
+ c = path[i];
+ while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) )
+ {
+ token[i] = c;
+ if ( i == MSDOS_NAME_MAX_WITH_DOT )
+ return MSDOS_INVALID_TOKEN;
+ if ( !msdos_is_valid_name_char(c) )
+ return MSDOS_INVALID_TOKEN;
+ c = path [++i];
+ }
+
+ /*
+ * Copy a seperator into token.
+ */
+ if ( i == 0 )
+ {
+ token[i] = c;
+ if ( token[i] != '\0' )
+ {
+ i++;
+ type = MSDOS_CURRENT_DIR;
+ }
+ else
+ type = MSDOS_NO_MORE_PATH;
+ }
+ else if (token[ i-1 ] != '\0')
+ token[i] = '\0';
+
+ /*
+ * Set token_len to the number of characters copied.
+ */
+ *token_len = i;
+
+ /*
+ * If we copied something that was not a seperator see if
+ * it was a special name.
+ */
+ if ( type == MSDOS_NAME )
+ {
+ if ( strcmp( token, "..") == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOTDOT_NAME);
+ type = MSDOS_UP_DIR;
+ return type;
+ }
+
+ if ( strcmp( token, "." ) == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOT_NAME);
+ type = MSDOS_CURRENT_DIR;
+ return type;
+ }
+
+ rc = msdos_format_name('r', token, *token_len, ret_token, 0);
+ if ( rc != RC_OK )
+ return MSDOS_INVALID_TOKEN;
+ }
+ ret_token[MSDOS_NAME_MAX] = '\0';
+ return type;
+}
+
+
+/* msdos_find_name --
+ * Find the node which correspondes to the name, open fat-file which
+ * correspondes to the found node and close fat-file which correspondes
+ * to the node we searched in.
+ *
+ * PARAMETERS:
+ * parent_loc - parent node description
+ * name - name to find
+ *
+ * RETURNS:
+ * RC_OK and updated 'parent_loc' on success, or -1 if error
+ * occured (errno set apropriately)
+ *
+ */
+int
+msdos_find_name(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ fat_auxiliary_t aux;
+ unsigned short time_val = 0;
+ unsigned short date = 0;
+ unsigned char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+
+ memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * find the node which correspondes to the name in the directory pointed by
+ * 'parent_loc'
+ */
+ rc = msdos_get_name_node(parent_loc, name, &aux, node_entry);
+ if (rc != RC_OK)
+ return rc;
+
+ /* open fat-file corresponded to the found node */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * I don't like this if, but: we should do it , or should write new file
+ * size and first cluster num to the disk after each write operation
+ * (even if one byte is written - that is TOO non-optimize) because
+ * otherwise real values of these fields stored in fat-file descriptor
+ * may be accidentely rewritten with wrong values stored on the disk
+ */
+ if (fat_fd->links_num == 1)
+ {
+ fat_fd->info_cln = aux.cln;
+ fat_fd->info_ofs = aux.ofs;
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
+ fat_fd->first_char = *MSDOS_DIR_NAME(node_entry);
+
+ time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
+ date = *MSDOS_DIR_WRITE_DATE(node_entry);
+
+ fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date));
+
+ if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
+ {
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ rc = fat_file_size(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+ }
+ else
+ {
+ fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
+ fat_fd->fat_file_type = FAT_FILE;
+ fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
+ }
+
+ /* these data is not actual for zero-length fat-file */
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ if ((fat_fd->fat_file_size != 0) &&
+ (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
+ {
+ fat_fd->map.last_cln = fat_fd->cln;
+ }
+ else
+ {
+ fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+ }
+ }
+
+ /* close fat-file corresponded to the node we searched in */
+ rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* update node_info_ptr field */
+ parent_loc->node_access = fat_fd;
+
+ return rc;
+}
+
+/* msdos_get_name_node --
+ * This routine is used in two ways: for a new mode creation (a) or for
+ * search the node which correspondes to the name parameter (b).
+ * In case (a) 'name' should be set up to NULL and 'name_dir_entry' should
+ * point to initialized 32 bytes structure described a new node.
+ * In case (b) 'name' should contain a valid string.
+ *
+ * (a): reading fat-file which correspondes to directory we are going to
+ * create node in. If free slot is found write contents of
+ * 'name_dir_entry' into it. If reach end of fat-file and no free
+ * slot found, write 32 bytes to the end of fat-file.
+ *
+ * (b): reading fat-file which correspondes to directory and trying to
+ * find slot with the name field == 'name' parameter
+ *
+ *
+ * PARAMETERS:
+ * parent_loc - node description to create node in or to find name in
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if
+ * error occured (errno set apropriately)
+ *
+ */
+int
+msdos_get_name_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = parent_loc->node_access;
+ unsigned32 dotdot_cln = 0;
+
+ /* find name in fat-file which correspondes to the directory */
+ rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, name, paux,
+ name_dir_entry);
+ if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
+ return rc;
+
+ /* if we search for valid name and name not found -> return */
+ if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name != NULL))
+ return rc;
+
+ /*
+ * if we try to create new entry and the directory is not big enough
+ * currently - try to enlarge directory
+ */
+ if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name == NULL))
+ {
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd,
+ fat_fd->fat_file_size,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ name_dir_entry);
+ if (ret == -1)
+ return -1;
+
+ /* on success directory is enlarged by a new cluster */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* get cluster num where a new node located */
+ rc = fat_file_ioctl(parent_loc->mt_entry, fat_fd, F_CLU_NUM,
+ fat_fd->fat_file_size - 1, &paux->cln);
+
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * if new cluster allocated succesfully then new node is at very
+ * beginning of the cluster (offset is computed in bytes)
+ */
+ paux->ofs = 0;
+ return RC_OK;
+ }
+
+ /*
+ * if we have deal with ".." - it is a special case :(((
+ *
+ * Really, we should return cluster num and offset not of ".." slot, but
+ * slot which correspondes to real directory name.
+ */
+ if ((rc == RC_OK) && (name != NULL))
+ {
+ if (strncmp(name, MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry));
+
+ /* are we right under root dir ? */
+ if (dotdot_cln == 0)
+ {
+ /*
+ * we can relax about first_char field - it never should be
+ * used for root dir
+ */
+ paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
+ paux->ofs = 0;
+ }
+ else
+ {
+ rc = msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ parent_loc->mt_entry,
+ dotdot_cln,
+ paux,
+ name_dir_entry
+ );
+ if (rc != RC_OK)
+ return rc;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+ * msdos_get_dotdot_dir_info_cluster_num_and_offset
+ *
+ * Unfortunately, in general, we cann't work here in fat-file ideologic
+ * (open fat_file "..", get ".." and ".", open "..", find an entry ...)
+ * because if we open
+ * fat-file ".." it may happend that we have two different fat-file
+ * descriptors ( for real name of directory and ".." name ) for a single
+ * file ( cluster num of both pointers to the same cluster )
+ * But...we do it because we protected by semaphore
+ *
+ */
+
+/* msdos_get_dotdot_dir_info_cluster_num_and_offset --
+ * Get cluster num and offset not of ".." slot, but slot which correspondes
+ * to real directory name.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - data cluster num extracted drom ".." slot
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned char dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char cur_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned32 cl4find = 0;
+
+ memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(cur_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * open fat-file corresponded to ".."
+ */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ fat_fd->info_cln = paux->cln;
+ fat_fd->info_ofs = paux->ofs;
+ fat_fd->cln = cln;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find "." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux,
+ dot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find ".." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux,
+ dotdot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
+
+ /* close fat-file corresponded to ".." directory */
+ rc = fat_file_close(mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ return rc;
+
+ if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ {
+ /*
+ * we handle root dir for all FAT types in the same way with the
+ * ordinary directories ( through fat_file_* calls )
+ */
+ paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
+ paux->ofs = 0;
+ }
+
+ /* open fat-file corresponded to second ".." */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ fat_fd->info_cln = paux->cln;
+ fat_fd->info_ofs = paux->ofs;
+
+ if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ fat_fd->cln = fs_info->fat.vol.rdir_cl;
+ else
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
+
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* in this directory find slot with specified cluster num */
+ rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
+ paux, dir_entry);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+ rc = fat_file_close(mt_entry, fat_fd);
+ return rc;
+}
+
+
+/* msdos_set_dir_wrt_time_and_date --
+ * Write last write date and time for a file to the disk (to corresponded
+ * 32bytes node)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned short time_val;
+ unsigned short date;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ msdos_date_unix2dos(fat_fd->mtime, &time_val, &date);
+
+ /*
+ * calculate input for _fat_block_write: convert (cluster num, offset) to
+ * (sector num, new offset)
+ */
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ /* byte points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ time_val = CT_LE_W(time_val);
+ ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET,
+ 2, (char *)(&time_val));
+ date = CT_LE_W(date);
+ ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET,
+ 2, (char *)(&date));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_set_first_cluster_num --
+ * Write number of first cluster of the file to the disk (to corresponded
+ * 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_set_first_cluster_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 new_cln = fat_fd->cln;
+ unsigned16 le_cl_low = 0;
+ unsigned16 le_cl_hi = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ /*
+ * calculate input for _fat_block_write: convert (cluster num, offset) to
+ * (sector num, new offset)
+ */
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ /* byte from points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ le_cl_low = CT_LE_W((unsigned16)(new_cln & 0x0000FFFF));
+ ret1 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
+ (char *)(&le_cl_low));
+ le_cl_hi = CT_LE_W((unsigned16)((new_cln & 0xFFFF0000) >> 16));
+ ret2 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
+ (char *)(&le_cl_hi));
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+
+/* msdos_set_file size --
+ * Write file size of the file to the disk (to corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_new_length = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1));
+
+ le_new_length = CT_LE_L((fat_fd->fat_file_size));
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
+ (char *)(&le_new_length));
+ if ( ret < 0 )
+ return -1;
+
+ return RC_OK;
+}
+
+/*
+ * We should not check whether this routine is called for root dir - it
+ * never can happend
+ */
+
+/* msdos_set_first_char4file_name --
+ * Write first character of the name of the file to the disk (to
+ * corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cl - number of cluster
+ * ofs - offset inside cluster
+ * fchar - character to set up
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately)
+ *
+ */
+int
+msdos_set_first_char4file_name(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char fchar
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cl);
+ sec += (ofs >> fs_info->fat.vol.sec_log2);
+ byte = (ofs & (fs_info->fat.vol.bps - 1));
+
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1,
+ &fchar);
+ if ( ret < 0)
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_dir_is_empty --
+ * Check whether directory which correspondes to the fat-file descriptor is
+ * empty.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * ret_val - placeholder for result
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_dir_is_empty(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0, i = 0;
+
+ /* dir is not empty */
+ *ret_val = FALSE;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
+ fs_info->fat.vol.bps,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ assert(ret == fs_info->fat.vol.bps);
+
+ for (i = 0;
+ i < fs_info->fat.vol.bps;
+ i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_DOTDOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0))
+ continue;
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ *ret_val = TRUE;
+ return RC_OK;
+ }
+ return RC_OK;
+ }
+ j++;
+ }
+ *ret_val = TRUE;
+ return RC_OK;
+}
+
+
+/* msdos_find_name_in_fat_file --
+ * This routine is used in two ways: for a new mode creation (a) or for
+ * search the node which correspondes to the 'name' parameter (b).
+ * In case (a) name should be set up to NULL and 'name_dir_entry' should
+ * point to initialized 32 bytes structure described a new node.
+ * In case (b) 'name' should contain a valid string.
+ *
+ * (a): reading fat-file corresponded to directory we are going to create
+ * node in. If found free slot write contents of name_dir_entry into
+ * it.
+ *
+ * (b): reading fat-file corresponded to directory and trying to find slot
+ * with the name field == name parameter
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ */
+int
+msdos_find_name_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 i = 0, j = 0;
+ unsigned32 bts2rd = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
+ bts2rd = fat_fd->fat_file_size;
+ else
+ bts2rd = fs_info->fat.vol.bpc;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ set_errno_and_return_minus_one(EIO);
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* is the entry empty ? */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
+ ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY))
+ {
+ /* whether we are looking for an empty entry */
+ if (name == NULL)
+ {
+ /* get current cluster number */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ /* offset is computed in bytes */
+ paux->ofs = i;
+
+ /* write new node entry */
+ ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ name_dir_entry);
+ if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ /*
+ * we don't update fat_file_size here - it should not
+ * increase
+ */
+ return RC_OK;
+ }
+
+ /*
+ * if name != NULL and there is no more entries in the
+ * directory - return name-not-found
+ */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY))
+ return MSDOS_NAME_NOT_FOUND_ERR;
+ }
+ else
+ {
+ /* entry not empty and name != NULL -> compare names */
+ if (name != NULL)
+ {
+ if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name,
+ MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ /*
+ * we get the entry we looked for - fill auxiliary
+ * structure and copy all 32 bytes of the entry
+ */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ /* offset is computed in bytes */
+ paux->ofs = i;
+ memcpy(name_dir_entry,(fs_info->cl_buf + i),
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
+
+/* msdos_find_node_by_cluster_num_in_fat_file --
+ * Find node with specified number of cluster in fat-file.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * cl4find - number of cluster to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured
+ *
+ */
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 bts2rd = 0;
+ unsigned32 i = 0, j = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
+ bts2rd = fat_fd->fat_file_size;
+ else
+ bts2rd = fs_info->fat.vol.bpc;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * bts2rd, bts2rd,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
+ set_errno_and_return_minus_one( EIO );
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* if this and all rest entries are empty - return not-found */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ return MSDOS_NAME_NOT_FOUND_ERR;
+
+ /* if this entry is empty - skip it */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY)
+ continue;
+
+ /* if get a non-empty entry - compare clusters num */
+ if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find)
+ {
+ /* on success fill aux structure and copy all 32 bytes */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd,
+ &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ paux->ofs = i;
+ memcpy(dir_entry, fs_info->cl_buf + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_mknod.c b/c/src/exec/libfs/src/dosfs/msdos_mknod.c
new file mode 100644
index 0000000000..5e32dbf3bf
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_mknod.c
@@ -0,0 +1,90 @@
+/*
+ * Routine for node creation in MSDOS filesystem.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_mknod --
+ * The following function checks spelling and formats name for a new node,
+ * determines type of the node to be created and creates it.
+ *
+ * PARAMETERS:
+ * token - non-formatted name of a new node
+ * mode - node type
+ * dev - dev
+ * pathloc - parent directory description
+ *
+ * RETURNS:
+ * RC_OK on succes, or -1 if error occured and set errno
+ *
+ */
+int
+msdos_mknod(
+ const char *token,
+ mode_t mode,
+ dev_t dev,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ msdos_token_types_t type = 0;
+ char new_name[ MSDOS_NAME_MAX + 1 ];
+ int len;
+
+ /* check spelling and format new node name */
+ msdos_get_token(token, new_name, &len);
+
+ /*
+ * Figure out what type of msdos node this is.
+ */
+ if (S_ISDIR(mode))
+ {
+ type = MSDOS_DIRECTORY;
+ }
+ else if (S_ISREG(mode))
+ {
+ type = MSDOS_REGULAR_FILE;
+ }
+ else
+ set_errno_and_return_minus_one(EINVAL);
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* Create an MSDOS node */
+ rc = msdos_creat_node(pathloc, type, new_name, mode);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/exec/libfs/src/dosfs/msdos_node_type.c b/c/src/exec/libfs/src/dosfs/msdos_node_type.c
new file mode 100644
index 0000000000..517dabda3f
--- /dev/null
+++ b/c/src/exec/libfs/src/dosfs/msdos_node_type.c
@@ -0,0 +1,58 @@
+/*
+ * The following returns the type of node that the loc refers to.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_node_type --
+ * Determine type of the node that the pathloc refers to.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * node type
+ *
+ */
+rtems_filesystem_node_types_t
+msdos_node_type(rtems_filesystem_location_info_t *pathloc)
+{
+ fat_file_fd_t *fat_fd;
+
+ /*
+ * we don't need to obtain the volume semaphore here because node_type_h
+ * call always follows evalpath_h call(hence link increment occured) and
+ * hence node_access memory can't be freed during processing node_type_h
+ * call
+ */
+ fat_fd = pathloc->node_access;
+
+ return fat_fd->fat_file_type;
+}
diff --git a/c/src/exec/libfs/wrapup/Makefile.am b/c/src/exec/libfs/wrapup/Makefile.am
index 5dfd76e83d..13406dcb5f 100644
--- a/c/src/exec/libfs/wrapup/Makefile.am
+++ b/c/src/exec/libfs/wrapup/Makefile.am
@@ -13,7 +13,9 @@ include $(top_srcdir)/../../../automake/lib.am
IMFSLIB = ../src/imfs/$(ARCH)/libimfs.a
-TMP_LIBS = $(IMFSLIB)
+DOSFSLIB = ../src/dosfs/$(ARCH)/libdosfs.a
+
+TMP_LIBS = $(IMFSLIB) $(DOSFSLIB)
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@
diff --git a/c/src/libfs/ChangeLog b/c/src/libfs/ChangeLog
index b4dd8e9f61..4166f2e369 100644
--- a/c/src/libfs/ChangeLog
+++ b/c/src/libfs/ChangeLog
@@ -1,3 +1,20 @@
+2002-02-28 Victor V. Vengerov <vvv@oktet.ru>
+
+ * DOS filesystem including FAT12, FAT16, and FAT32 support submitted.
+ * src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in,
+ src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c,
+ src/dosfs/fat.h, src/dosfs/fat_fat_operations.c,
+ src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c,
+ src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c,
+ src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c,
+ src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c,
+ src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c,
+ src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c,
+ src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c,
+ src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files.
+ * configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to
+ reflect addition.
+
2002-01-07 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* src/imfs/imfs_load_tar.c: Add include <sys/types.h>.
diff --git a/c/src/libfs/configure.ac b/c/src/libfs/configure.ac
index 4e2adeb1b5..7f36fac28e 100644
--- a/c/src/libfs/configure.ac
+++ b/c/src/libfs/configure.ac
@@ -5,6 +5,7 @@
AC_PREREQ(2.52)
AC_INIT
AC_CONFIG_SRCDIR([src/imfs/imfs.h])
+AC_CONFIG_SRCDIR([src/dosfs/dosfs.h])
RTEMS_TOP(../../..)
AC_CONFIG_AUX_DIR(../../..)
@@ -27,11 +28,13 @@ RTEMS_CANONICALIZE_TOOLS
AM_CONDITIONAL(UNIX,test x"$RTEMS_CPU" = x"unix")
AM_CONFIG_HEADER(src/imfs/config.h)
+AM_CONFIG_HEADER(src/dosfs/config.h)
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
src/Makefile
src/imfs/Makefile
+src/dosfs/Makefile
wrapup/Makefile
])
AC_OUTPUT
diff --git a/c/src/libfs/src/Makefile.am b/c/src/libfs/src/Makefile.am
index 126a226126..fcd82899b4 100644
--- a/c/src/libfs/src/Makefile.am
+++ b/c/src/libfs/src/Makefile.am
@@ -4,7 +4,7 @@
AUTOMAKE_OPTIONS = foreign 1.4
-SUBDIRS = imfs
+SUBDIRS = imfs dosfs
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libfs/src/dosfs/.cvsignore b/c/src/libfs/src/dosfs/.cvsignore
new file mode 100644
index 0000000000..7bb609bf24
--- /dev/null
+++ b/c/src/libfs/src/dosfs/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+config.h
+config.h.in
+stamp-h
+stamp-h.in
diff --git a/c/src/libfs/src/dosfs/Makefile.am b/c/src/libfs/src/dosfs/Makefile.am
new file mode 100644
index 0000000000..44c9f4cd2f
--- /dev/null
+++ b/c/src/libfs/src/dosfs/Makefile.am
@@ -0,0 +1,80 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+INCLUDES = -I.
+
+LIBNAME = libdosfs
+LIB = ${ARCH}/${LIBNAME}.a
+
+FATFS_C_FILES = fat.c fat_fat_operations.c fat_file.c
+
+DOSFS_C_FILES = msdos_create.c msdos_dir.c msdos_eval.c msdos_file.c \
+ msdos_free.c msdos_fsunmount.c msdos_handlers_dir.c \
+ msdos_handlers_file.c msdos_init.c msdos_initsupp.c \
+ msdos_misc.c msdos_mknod.c msdos_node_type.c
+
+
+UNIX_C_FILES = msdos_unixstub.c
+
+EMBEDDED_C_FILES = $(FATFS_C_FILES) $(DOSFS_C_FILES)
+
+COMMON_C_FILES =
+
+if UNIX
+C_FILES = $(COMMON_C_FILES) $(UNIX_C_FILES)
+else
+C_FILES = $(COMMON_C_FILES) $(EMBEDDED_C_FILES)
+endif
+C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
+
+include_HEADERS = fat.h fat_fat_operations.h \
+ fat_file.h msdos.h dosfs.h
+SYS_H_FILES =
+RTEMS_H_FILES =
+noinst_HEADERS =
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+PREINSTALL_FILES = $(PROJECT_INCLUDE) $(PROJECT_INCLUDE)/rtems \
+ $(PROJECT_INCLUDE)/sys $(include_HEADERS:%=$(PROJECT_INCLUDE)/%) \
+ $(RTEMS_H_FILES:%=$(PROJECT_INCLUDE)/rtems/%) \
+ $(SYS_H_FILES:%=$(PROJECT_INCLUDE)/sys/%)
+
+$(PROJECT_INCLUDE):
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/sys:
+ @$(mkinstalldirs) $@
+
+$(PROJECT_INCLUDE)/%.h: %.h
+ $(INSTALL_DATA) $< $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+$(PROJECT_INCLUDE)/sys/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+OBJS = $(C_O_FILES)
+
+#
+# Add local stuff here using +=
+#
+
+AM_CFLAGS += $(LIBC_DEFINES)
+
+all-local: ${ARCH} $(LIB)
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+DOC_FILES =
+
+EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \
+ $(UNIX_C_FILES) $(RTEMS_H_FILES) $(SYS_H_FILES)
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/c/src/libfs/src/dosfs/config.h.in b/c/src/libfs/src/dosfs/config.h.in
new file mode 100644
index 0000000000..489947fd57
--- /dev/null
+++ b/c/src/libfs/src/dosfs/config.h.in
@@ -0,0 +1 @@
+/* src/dosfs/config.h.in. Generated automatically from configure.in by autoheader. */
diff --git a/c/src/libfs/src/dosfs/dosfs.h b/c/src/libfs/src/dosfs/dosfs.h
new file mode 100644
index 0000000000..4cea929d4c
--- /dev/null
+++ b/c/src/libfs/src/dosfs/dosfs.h
@@ -0,0 +1,31 @@
+/*
+ * dosfs.h
+ *
+ * Application interface to MSDOS filesystem.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_DOSFS_H__
+#define __DOSFS_DOSFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+extern rtems_filesystem_operations_table msdos_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_DOSFS_H__ */
diff --git a/c/src/libfs/src/dosfs/fat.c b/c/src/libfs/src/dosfs/fat.c
new file mode 100644
index 0000000000..852c104781
--- /dev/null
+++ b/c/src/libfs/src/dosfs/fat.c
@@ -0,0 +1,695 @@
+/*
+ * fat.c
+ *
+ * Low-level operations on a volume with FAT filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+
+/* _fat_block_read --
+ * This function reads 'count' bytes from device filesystem is mounted on,
+ * starts at 'start+offset' position where 'start' computed in sectors
+ * and 'offset' is offset inside sector (reading may cross sectors
+ * boundary; in this case assumed we want to read sequential sector(s))
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start - sector num to start read from
+ * offset - offset inside sector 'start'
+ * count - count of bytes to read
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes read on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+_fat_block_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ void *buff
+ )
+{
+ int rc = RC_OK;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ ssize_t cmpltd = 0;
+ unsigned32 blk = start;
+ unsigned32 ofs = offset;
+ bdbuf_buffer *block = NULL;
+ unsigned32 c = 0;
+
+ while (count > 0)
+ {
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ if (rc != RC_OK)
+ return rc;
+
+ c = MIN(count, (fs_info->vol.bps - ofs));
+ memcpy((buff + cmpltd), (block->buffer + ofs), c);
+
+ count -= c;
+ cmpltd += c;
+ blk++;
+ ofs = 0;
+ }
+ return cmpltd;
+}
+
+/* _fat_block_write --
+ * This function write 'count' bytes to device filesystem is mounted on,
+ * starts at 'start+offset' position where 'start' computed in sectors
+ * and 'offset' is offset inside sector (writing may cross sectors
+ * boundary; in this case assumed we want to write sequential sector(s))
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start - sector num to start read from
+ * offset - offset inside sector 'start'
+ * count - count of bytes to write
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+_fat_block_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ const void *buff)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ ssize_t cmpltd = 0;
+ unsigned32 blk = start;
+ unsigned32 ofs = offset;
+ bdbuf_buffer *block = NULL;
+ unsigned32 c = 0;
+
+ while(count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bps - ofs));
+
+ if (c == fs_info->vol.bps)
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
+ else
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ if (rc != RC_OK)
+ return rc;
+
+ memcpy((block->buffer + ofs), (buff + cmpltd), c);
+
+ fat_buf_mark_modified(fs_info);
+
+ count -= c;
+ cmpltd +=c;
+ blk++;
+ ofs = 0;
+ }
+ return cmpltd;
+}
+
+
+
+
+/* fat_cluster_read --
+ * wrapper for reading a whole cluster at once
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to read
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes read on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+fat_cluster_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ void *buff
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 fsec = 0;
+
+ fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
+
+ return _fat_block_read(mt_entry, fsec, 0,
+ fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+}
+
+/* fat_cluster_write --
+ * wrapper for writting a whole cluster at once
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to write
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+fat_cluster_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ const void *buff
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 fsec = 0;
+
+ fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
+
+ return _fat_block_write(mt_entry, fsec, 0,
+ fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+}
+
+/* fat_init_volume_info --
+ * Get inforamtion about volume on which filesystem is mounted on
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ register fat_vol_t *vol = &fs_info->vol;
+ unsigned32 data_secs = 0;
+ char boot_rec[FAT_MAX_BPB_SIZE];
+ char fs_info_sector[FAT_USEFUL_INFO_SIZE];
+ ssize_t ret = 0;
+ int fd;
+ struct stat stat_buf;
+ int i = 0;
+
+ rc = stat(mt_entry->dev, &stat_buf);
+ if (rc == -1)
+ return rc;
+
+ /* rtmes feature: no block devices, all are character devices */
+ if (!S_ISCHR(stat_buf.st_mode))
+ set_errno_and_return_minus_one(ENOTBLK);
+
+ /* check that device is registred as block device and lock it */
+ vol->dd = rtems_disk_lookup(stat_buf.st_dev);
+ if (vol->dd == NULL)
+ set_errno_and_return_minus_one(ENOTBLK);
+
+ vol->dev = stat_buf.st_dev;
+
+ fd = open(mt_entry->dev, O_RDONLY);
+ if (fd == -1)
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ ret = read(fd, (void *)boot_rec, FAT_MAX_BPB_SIZE);
+ if ( ret != FAT_MAX_BPB_SIZE )
+ {
+ close(fd);
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EIO );
+ }
+ close(fd);
+
+ vol->bps = FAT_BR_BYTES_PER_SECTOR(boot_rec);
+
+ if ( (vol->bps != 512) &&
+ (vol->bps != 1024) &&
+ (vol->bps != 2048) &&
+ (vol->bps != 4096))
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+
+ for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
+ i >>= 1, vol->sec_mul++);
+ for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
+ i >>= 1, vol->sec_log2++);
+
+ vol->spc = FAT_BR_SECTORS_PER_CLUSTER(boot_rec);
+ for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
+ i >>= 1, vol->spc_log2++);
+
+ /*
+ * According to M$ White Paper "bytes per cluster" value
+ * greater than 32K is invalid
+ */
+ if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one(EINVAL);
+ }
+
+ for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
+ i >>= 1, vol->bpc_log2++);
+
+ vol->fats = FAT_BR_FAT_NUM(boot_rec);
+ vol->fat_loc = FAT_BR_RESERVED_SECTORS_NUM(boot_rec);
+
+ vol->rdir_entrs = FAT_BR_FILES_PER_ROOT_DIR(boot_rec);
+
+ /* calculate the count of sectors occupied by the root directory */
+ vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
+ vol->bps;
+
+ vol->rdir_size = vol->rdir_secs << vol->sec_log2;
+
+ if ( (FAT_BR_SECTORS_PER_FAT(boot_rec)) != 0)
+ vol->fat_length = FAT_BR_SECTORS_PER_FAT(boot_rec);
+ else
+ vol->fat_length = FAT_BR_SECTORS_PER_FAT32(boot_rec);
+
+ vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
+ vol->rdir_secs;
+
+ /* for FAT12/16 root dir starts at(sector) */
+ vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
+
+ if ( (FAT_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
+ vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM16(boot_rec);
+ else
+ vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM32(boot_rec);
+
+ data_secs = vol->tot_secs - vol->data_fsec;
+
+ vol->data_cls = data_secs / vol->spc;
+
+ /* determine FAT type at least */
+ if ( vol->data_cls < FAT_FAT12_MAX_CLN)
+ {
+ vol->type = FAT_FAT12;
+ vol->mask = FAT_FAT12_MASK;
+ vol->eoc_val = FAT_FAT12_EOC;
+ }
+ else
+ {
+ if ( vol->data_cls < FAT_FAT16_MAX_CLN)
+ {
+ vol->type = FAT_FAT16;
+ vol->mask = FAT_FAT16_MASK;
+ vol->eoc_val = FAT_FAT16_EOC;
+ }
+ else
+ {
+ vol->type = FAT_FAT32;
+ vol->mask = FAT_FAT32_MASK;
+ vol->eoc_val = FAT_FAT32_EOC;
+ }
+ }
+
+ if (vol->type == FAT_FAT32)
+ {
+ vol->rdir_cl = FAT_BR_FAT32_ROOT_CLUSTER(boot_rec);
+
+ vol->mirror = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
+ if (vol->mirror)
+ vol->afat = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
+ else
+ vol->afat = 0;
+
+ vol->info_sec = FAT_BR_FAT32_FS_INFO_SECTOR(boot_rec);
+ if( vol->info_sec == 0 )
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+ else
+ {
+ ret = _fat_block_read(mt_entry, vol->info_sec , 0,
+ FAT_FSI_LEADSIG_SIZE, fs_info_sector);
+ if ( ret < 0 )
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ if (FAT_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
+ FAT_FSINFO_LEAD_SIGNATURE_VALUE)
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+ else
+ {
+ ret = _fat_block_read(mt_entry, vol->info_sec , FAT_FSI_INFO,
+ FAT_USEFUL_INFO_SIZE, fs_info_sector);
+ if ( ret < 0 )
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ vol->free_cls = FAT_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
+ vol->next_cl = FAT_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
+ rc = fat_fat32_update_fsinfo_sector(mt_entry, 0xFFFFFFFF,
+ 0xFFFFFFFF);
+ if ( rc != RC_OK )
+ {
+ rtems_disk_release(vol->dd);
+ return rc;
+ }
+ }
+ }
+ }
+ else
+ {
+ vol->rdir_cl = 0;
+ vol->mirror = 0;
+ vol->afat = 0;
+ vol->free_cls = 0xFFFFFFFF;
+ vol->next_cl = 0xFFFFFFFF;
+ }
+ vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
+
+ /* set up collection of fat-files fd */
+ fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
+ if ( fs_info->vhash == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ _Chain_Initialize_empty(fs_info->vhash + i);
+
+ fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
+ if ( fs_info->rhash == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ _Chain_Initialize_empty(fs_info->rhash + i);
+
+ fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
+ fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
+ fs_info->index = 0;
+ fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
+ if ( fs_info->uino == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ fs_info->sec_buf = (char *)calloc(vol->bps, sizeof(char));
+ if (fs_info->sec_buf == NULL)
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ free(fs_info->uino);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+
+ return RC_OK;
+}
+
+/* fat_shutdown_drive --
+ * Free all allocated resources and synchronize all necessary data
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ int i = 0;
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ rc = fat_fat32_update_fsinfo_sector(mt_entry, fs_info->vol.free_cls,
+ fs_info->vol.next_cl);
+ if ( rc != RC_OK )
+ rc = -1;
+ }
+
+ fat_buf_release(fs_info);
+
+ if (rtems_bdbuf_syncdev(fs_info->vol.dev) != RTEMS_SUCCESSFUL)
+ rc = -1;
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ {
+ Chain_Node *node = NULL;
+ Chain_Control *the_chain = fs_info->vhash + i;
+
+ while ( (node = _Chain_Get(the_chain)) != NULL )
+ free(node);
+ }
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ {
+ Chain_Node *node = NULL;
+ Chain_Control *the_chain = fs_info->rhash + i;
+
+ while ( (node = _Chain_Get(the_chain)) != NULL )
+ free(node);
+ }
+
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+
+ free(fs_info->uino);
+ free(fs_info->sec_buf);
+ rtems_disk_release(fs_info->vol.dd);
+
+ if (rc)
+ errno = EIO;
+ return rc;
+}
+
+/* fat_init_clusters_chain --
+ * Zeroing contents of all clusters in the chain
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start_cluster_num - num of first cluster in the chain
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_init_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start_cln
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = start_cln;
+ char *buf;
+
+ buf = calloc(fs_info->vol.bpc, sizeof(char));
+ if ( buf == NULL )
+ set_errno_and_return_minus_one( EIO );
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ ret = fat_cluster_write(mt_entry, cur_cln, buf);
+ if ( ret == -1 )
+ {
+ free(buf);
+ return -1;
+ }
+
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ {
+ free(buf);
+ return rc;
+ }
+
+ }
+ free(buf);
+ return rc;
+}
+
+#define FAT_UNIQ_INO_BASE 0x0FFFFF00
+
+#define FAT_UNIQ_INO_IS_BUSY(index, arr) \
+ (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
+
+#define FAT_SET_UNIQ_INO_BUSY(index, arr) \
+ ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
+
+#define FAT_SET_UNIQ_INO_FREE(index, arr) \
+ ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
+
+/* fat_get_unique_ino --
+ * Allocate unique ino from unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * unique inode number on success, or 0 if there is no free unique inode
+ * number in the pool
+ *
+ * ATTENTION:
+ * 0 means FAILED !!!
+ *
+ */
+unsigned32
+fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0;
+ rtems_boolean resrc_unsuff = FALSE;
+
+ while (!resrc_unsuff)
+ {
+ for (j = 0; j < fs_info->uino_pool_size; j++)
+ {
+ if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
+ {
+ FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
+ return (fs_info->uino_base + fs_info->index);
+ }
+ fs_info->index++;
+ if (fs_info->index >= fs_info->uino_pool_size)
+ fs_info->index = 0;
+ }
+
+ if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
+ {
+ fs_info->uino_pool_size <<= 1;
+ fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
+ if (fs_info->uino != NULL)
+ fs_info->index = fs_info->uino_pool_size;
+ else
+ resrc_unsuff = TRUE;
+ }
+ else
+ resrc_unsuff = TRUE;
+ }
+ return 0;
+}
+
+/* fat_free_unique_ino --
+ * Return unique ino to unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * ino - inode number to free
+ *
+ * RETURNS:
+ * None
+ */
+void
+fat_free_unique_ino(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
+}
+
+/* fat_ino_is_unique --
+ * Test whether ino is from unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * ino - ino to be tested
+ *
+ * RETURNS:
+ * TRUE if ino is allocated from unique ino pool, FALSE otherwise
+ */
+inline rtems_boolean
+fat_ino_is_unique(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ return (ino >= fs_info->uino_base);
+}
+
+/* fat_fat32_update_fsinfo_sector --
+ * Synchronize fsinfo sector for FAT32 volumes
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * free_count - count of free clusters
+ * next_free - the next free cluster num
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_fat32_update_fsinfo_sector(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 free_count,
+ unsigned32 next_free
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_free_count = 0;
+ unsigned32 le_next_free = 0;
+
+ le_free_count = CT_LE_L(free_count);
+ le_next_free = CT_LE_L(next_free);
+
+ ret1 = _fat_block_write(mt_entry,
+ fs_info->vol.info_sec,
+ FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
+ 4,
+ (char *)(&le_free_count));
+
+ ret2 = _fat_block_write(mt_entry,
+ fs_info->vol.info_sec,
+ FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
+ 4,
+ (char *)(&le_next_free));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+ \ No newline at end of file
diff --git a/c/src/libfs/src/dosfs/fat.h b/c/src/libfs/src/dosfs/fat.h
new file mode 100644
index 0000000000..04a1f0f662
--- /dev/null
+++ b/c/src/libfs/src/dosfs/fat.h
@@ -0,0 +1,489 @@
+/*
+ * fat.h
+ *
+ * Constants/data structures/prototypes for low-level operations on a volume
+ * with FAT filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#ifndef __DOSFS_FAT_H__
+#define __DOSFS_FAT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/seterr.h>
+
+/* XXX: temporary hack :(( */
+#ifndef set_errno_and_return_minus_one
+#define set_errno_and_return_minus_one rtems_set_errno_and_return_minus_one
+#endif /* set_errno_and_return_minus_one */
+
+#include <rtems/score/cpu.h>
+#include <errno.h>
+#include <rtems/bdbuf.h>
+
+#define DBG1(x) x
+#define DBG2(x) x
+
+#ifndef RC_OK
+#define RC_OK 0x00000000
+#endif
+
+/*
+ * Remember that all FAT file system on disk data structure is
+ * "little endian"!
+ * (derived from linux)
+ */
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ *
+ * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian,
+ * BE = big-endian, c: W = word (16 bits), L = longword (32 bits)
+ */
+
+#if (CPU_BIG_ENDIAN == TRUE)
+# define CF_LE_W(v) CPU_swap_u16(v)
+# define CF_LE_L(v) CPU_swap_u32(v)
+# define CT_LE_W(v) CPU_swap_u16(v)
+# define CT_LE_L(v) CPU_swap_u32(v)
+#else
+# define CF_LE_W(v) (v)
+# define CF_LE_L(v) (v)
+# define CT_LE_W(v) (v)
+# define CT_LE_L(v) (v)
+#endif
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define FAT_HASH_SIZE 2
+#define FAT_HASH_MODULE FAT_HASH_SIZE
+
+
+#define FAT_SECTOR512_SIZE 512 /* sector size (bytes) */
+#define FAT_SECTOR512_BITS 9 /* log2(SECTOR_SIZE) */
+
+/* maximum + 1 number of clusters for FAT12 */
+#define FAT_FAT12_MAX_CLN 4085
+
+/* maximum + 1 number of clusters for FAT16 */
+#define FAT_FAT16_MAX_CLN 65525
+
+#define FAT_FAT12 0x01
+#define FAT_FAT16 0x02
+#define FAT_FAT32 0x04
+
+#define FAT_UNDEFINED_VALUE 0xFFFFFFFF
+
+#define FAT_FAT12_EOC 0x0FFF
+#define FAT_FAT16_EOC 0xFFFF
+#define FAT_FAT32_EOC 0x0FFFFFFF
+
+#define FAT_FAT12_FREE 0x0000
+#define FAT_FAT16_FREE 0x0000
+#define FAT_FAT32_FREE 0x00000000
+
+#define FAT_GENFAT_EOC 0xFFFFFFFF
+#define FAT_GENFAT_FREE 0x00000000
+
+#define FAT_FAT12_SHIFT 0x04
+
+#define FAT_FAT12_MASK 0x00000FFF
+#define FAT_FAT16_MASK 0x0000FFFF
+#define FAT_FAT32_MASK 0x0FFFFFFF
+
+#define FAT_MAX_BPB_SIZE 90
+
+/* size of useful information in FSInfo sector */
+#define FAT_USEFUL_INFO_SIZE 12
+
+#define FAT_VAL8(x, ofs) (unsigned8)(*((unsigned8 *)(x) + (ofs)))
+
+#define FAT_VAL16(x, ofs) \
+ (unsigned16)( (*((unsigned8 *)(x) + (ofs))) | \
+ ((*((unsigned8 *)(x) + (ofs) + 1)) << 8) )
+
+#define FAT_VAL32(x, ofs) \
+ (unsigned32)( (*((unsigned8 *)(x) + (ofs))) | \
+ ((*((unsigned8 *)(x) + (ofs) + 1)) << 8) | \
+ ((*((unsigned8 *)(x) + (ofs) + 2)) << 16) | \
+ ((*((unsigned8 *)(x) + (ofs) + 3)) << 24) )
+
+/* macros to access boot sector fields */
+#define FAT_BR_BYTES_PER_SECTOR(x) FAT_VAL16(x, 11)
+#define FAT_BR_SECTORS_PER_CLUSTER(x) FAT_VAL8(x, 13)
+#define FAT_BR_RESERVED_SECTORS_NUM(x) FAT_VAL16(x, 14)
+#define FAT_BR_FAT_NUM(x) FAT_VAL8(x, 16)
+#define FAT_BR_FILES_PER_ROOT_DIR(x) FAT_VAL16(x, 17)
+#define FAT_BR_TOTAL_SECTORS_NUM16(x) FAT_VAL16(x, 19)
+#define FAT_BR_MEDIA(x) FAT_VAL8(x, 21)
+#define FAT_BR_SECTORS_PER_FAT(x) FAT_VAL16(x, 22)
+#define FAT_BR_TOTAL_SECTORS_NUM32(x) FAT_VAL32(x, 32)
+#define FAT_BR_SECTORS_PER_FAT32(x) FAT_VAL32(x, 36)
+#define FAT_BR_EXT_FLAGS(x) FAT_VAL16(x, 40)
+#define FAT_BR_FAT32_ROOT_CLUSTER(x) FAT_VAL32(x, 44)
+#define FAT_BR_FAT32_FS_INFO_SECTOR(x) FAT_VAL16(x, 48)
+#define FAT_FSINFO_LEAD_SIGNATURE(x) FAT_VAL32(x, 0)
+/*
+ * I read FSInfo sector from offset 484 to access the information, so offsets
+ * of these fields a relative
+ */
+#define FAT_FSINFO_FREE_CLUSTER_COUNT(x) FAT_VAL32(x, 4)
+#define FAT_FSINFO_NEXT_FREE_CLUSTER(x) FAT_VAL32(x, 8)
+
+#define FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET 488
+
+#define FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET 492
+
+#define FAT_RSRVD_CLN 0x02
+
+#define FAT_FSINFO_LEAD_SIGNATURE_VALUE 0x41615252
+
+#define FAT_FSI_LEADSIG_SIZE 0x04
+
+#define FAT_FSI_INFO 484
+
+#define MS_BYTES_PER_CLUSTER_LIMIT 0x8000 /* 32K */
+
+#define FAT_BR_EXT_FLAGS_MIRROR 0x0080
+
+#define FAT_BR_EXT_FLAGS_FAT_NUM 0x000F
+
+
+#define FAT_DIRENTRY_SIZE 32
+
+#define FAT_DIRENTRIES_PER_SEC512 16
+
+/*
+ * Volume descriptor
+ * Description of the volume the FAT filesystem is located on - generally
+ * the fields of the structure corresponde to Boot Sector and BPB Srtucture
+ * (see M$ White Paper) fields
+ */
+typedef struct fat_vol_s
+{
+ unsigned16 bps; /* bytes per sector */
+ unsigned8 sec_log2; /* log2 of bps */
+ unsigned8 sec_mul; /* log2 of 512bts sectors number per sector */
+ unsigned8 spc; /* sectors per cluster */
+ unsigned8 spc_log2; /* log2 of spc */
+ unsigned16 bpc; /* bytes per cluster */
+ unsigned8 bpc_log2; /* log2 of bytes per cluster */
+ unsigned8 fats; /* number of FATs */
+ unsigned8 type; /* FAT type */
+ unsigned32 mask;
+ unsigned32 eoc_val;
+ unsigned16 fat_loc; /* FAT start */
+ unsigned32 fat_length; /* sectors per FAT */
+ unsigned32 rdir_loc; /* root directory start */
+ unsigned16 rdir_entrs; /* files per root directory */
+ unsigned32 rdir_secs; /* sectors per root directory */
+ unsigned32 rdir_size; /* root directory size in bytes */
+ unsigned32 tot_secs; /* total count of sectors */
+ unsigned32 data_fsec; /* first data sector */
+ unsigned32 data_cls; /* count of data clusters */
+ unsigned32 rdir_cl; /* first cluster of the root directory */
+ unsigned16 info_sec; /* FSInfo Sector Structure location */
+ unsigned32 free_cls; /* last known free clusters count */
+ unsigned32 next_cl; /* next free cluster number */
+ unsigned8 mirror; /* mirroring enabla/disable */
+ unsigned32 afat_loc; /* active FAT location */
+ unsigned8 afat; /* the number of active FAT */
+ dev_t dev; /* device ID */
+ disk_device *dd; /* disk device (see libblock) */
+ void *private_data; /* reserved */
+} fat_vol_t;
+
+
+typedef struct fat_cache_s
+{
+ unsigned32 blk_num;
+ rtems_boolean modified;
+ unsigned8 state;
+ bdbuf_buffer *buf;
+} fat_cache_t;
+
+/*
+ * This structure identifies the instance of the filesystem on the FAT
+ * ("fat-file") level.
+ */
+typedef struct fat_fs_info_s
+{
+ fat_vol_t vol; /* volume descriptor */
+ Chain_Control *vhash; /* "vhash" of fat-file descriptors */
+ Chain_Control *rhash; /* "rhash" of fat-file descriptors */
+ char *uino; /* array of unique ino numbers */
+ unsigned32 index;
+ unsigned32 uino_pool_size; /* size */
+ unsigned32 uino_base;
+ fat_cache_t c; /* cache */
+ unsigned8 *sec_buf; /* just placeholder for anything */
+} fat_fs_info_t;
+
+/*
+ * if the name we looking for is file we store not only first data cluster
+ * number, but and cluster number and offset for directory entry for this
+ * name
+ */
+typedef struct fat_auxiliary_s
+{
+ unsigned32 cln;
+ unsigned32 ofs;
+} fat_auxiliary_t;
+
+#define FAT_FAT_OFFSET(fat_type, cln) \
+ ((fat_type) & FAT_FAT12 ? ((cln) + ((cln) >> 1)) : \
+ (fat_type) & FAT_FAT16 ? ((cln) << 1) : \
+ ((cln) << 2))
+
+#define FAT_CLUSTER_IS_ODD(n) ((n) & 0x0001)
+
+#define FAT12_SHIFT 0x4 /* half of a byte */
+
+/* initial size of array of unique ino */
+#define FAT_UINO_POOL_INIT_SIZE 0x100
+
+/* cache support */
+#define FAT_CACHE_EMPTY 0x0
+#define FAT_CACHE_ACTUAL 0x1
+
+#define FAT_OP_TYPE_READ 0x1
+#define FAT_OP_TYPE_GET 0x2
+
+static inline unsigned32
+fat_cluster_num_to_sector_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln
+ )
+{
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ if ( (cln == 0) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)) )
+ return fs_info->vol.rdir_loc;
+
+ return (((cln - FAT_RSRVD_CLN) << fs_info->vol.spc_log2) +
+ fs_info->vol.data_fsec);
+}
+
+static inline unsigned32
+fat_cluster_num_to_sector512_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ if (cln == 1)
+ return 1;
+
+ return (fat_cluster_num_to_sector_num(mt_entry, cln) <<
+ fs_info->vol.sec_mul);
+}
+
+static inline int
+fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type,
+ bdbuf_buffer **buf)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned8 i;
+ rtems_boolean sec_of_fat;
+
+
+ if (fs_info->c.state == FAT_CACHE_EMPTY)
+ {
+ if (op_type == FAT_OP_TYPE_READ)
+ sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
+ else
+ sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.blk_num = blk;
+ fs_info->c.state = FAT_CACHE_ACTUAL;
+ }
+
+ sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
+ (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+
+ if (fs_info->c.blk_num != blk)
+ {
+ if (fs_info->c.modified)
+ {
+ if (sec_of_fat && !fs_info->vol.mirror)
+ memcpy(fs_info->sec_buf, fs_info->c.buf->buffer,
+ fs_info->vol.bps);
+
+ sc = rtems_bdbuf_release_modified(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.modified = 0;
+
+ if (sec_of_fat && !fs_info->vol.mirror)
+ {
+ bdbuf_buffer *b;
+
+ for (i = 1; i < fs_info->vol.fats; i++)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dev,
+ fs_info->c.blk_num +
+ fs_info->vol.fat_length * i,
+ &b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+ }
+ }
+ else
+ {
+ sc = rtems_bdbuf_release(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ }
+ if (op_type == FAT_OP_TYPE_READ)
+ sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
+ else
+ sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.blk_num = blk;
+ }
+ *buf = fs_info->c.buf;
+ return RC_OK;
+}
+
+
+static inline int
+fat_buf_release(fat_fs_info_t *fs_info)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned8 i;
+ rtems_boolean sec_of_fat;
+
+ if (fs_info->c.state == FAT_CACHE_EMPTY)
+ return RC_OK;
+
+ sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
+ (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+
+ if (fs_info->c.modified)
+ {
+ if (sec_of_fat && !fs_info->vol.mirror)
+ memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps);
+
+ sc = rtems_bdbuf_release_modified(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.modified = 0;
+
+ if (sec_of_fat && !fs_info->vol.mirror)
+ {
+ bdbuf_buffer *b;
+
+ for (i = 1; i < fs_info->vol.fats; i++)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dev,
+ fs_info->c.blk_num +
+ fs_info->vol.fat_length * i,
+ &b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+ }
+ }
+ else
+ {
+ sc = rtems_bdbuf_release(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ }
+ fs_info->c.state = FAT_CACHE_EMPTY;
+ return RC_OK;
+}
+
+static inline void
+fat_buf_mark_modified(fat_fs_info_t *fs_info)
+{
+ fs_info->c.modified = TRUE;
+}
+
+
+
+ssize_t
+_fat_block_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ void *buff);
+
+ssize_t
+_fat_block_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ const void *buff);
+
+ssize_t
+fat_cluster_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ void *buff);
+
+ssize_t
+fat_cluster_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ const void *buff);
+
+int
+fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+int
+fat_init_clusters_chain(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start_cln);
+
+unsigned32
+fat_cluster_num_to_sector_num(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln);
+
+int
+fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+
+unsigned32
+fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+rtems_boolean
+fat_ino_is_unique(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino);
+
+void
+fat_free_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino);
+
+int
+fat_fat32_update_fsinfo_sector(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 free_count,
+ unsigned32 next_free
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_H__ */
diff --git a/c/src/libfs/src/dosfs/fat_fat_operations.c b/c/src/libfs/src/dosfs/fat_fat_operations.c
new file mode 100644
index 0000000000..49b2ab70d3
--- /dev/null
+++ b/c/src/libfs/src/dosfs/fat_fat_operations.c
@@ -0,0 +1,445 @@
+/*
+ * fat_fat_operations.c
+ *
+ * General operations on File Allocation Table
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+
+/* fat_scan_fat_for_free_clusters --
+ * Allocate chain of free clusters from Files Allocation Table
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * chain - the number of the first allocated cluster (first cluster
+ * in the chain)
+ * count - count of clusters to allocate (chain length)
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ *
+ */
+int
+fat_scan_fat_for_free_clusters(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 *chain,
+ unsigned32 count,
+ unsigned32 *cls_added,
+ unsigned32 *last_cl
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cl4find = 2;
+ unsigned32 next_cln = 0;
+ unsigned32 save_cln = 0;
+ unsigned32 data_cls_val = fs_info->vol.data_cls + 2;
+ unsigned32 i = 2;
+
+ *cls_added = 0;
+
+ if (count == 0)
+ return rc;
+
+ if ((fs_info->vol.type & FAT_FAT32) &&
+ (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE))
+ cl4find = fs_info->vol.next_cl;
+
+ /*
+ * fs_info->vol.data_cls is exactly the count of data clusters
+ * starting at cluster 2, so the maximum valid cluster number is
+ * (fs_info->vol.data_cls + 1)
+ */
+ while (i < data_cls_val)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln);
+ if ( rc != RC_OK )
+ {
+ if (*cls_added != 0)
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ return rc;
+ }
+
+ if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)
+ {
+ /*
+ * We are enforced to process allocation of the first free cluster
+ * by separate 'if' statement because otherwise undo function
+ * wouldn't work properly
+ */
+ if (*cls_added == 0)
+ {
+ *chain = cl4find;
+ rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ {
+ /*
+ * this is the first cluster we tried to allocate so no
+ * cleanup activity needed
+ */
+ return rc;
+ }
+ }
+ else
+ {
+ /* set EOC value to new allocated cluster */
+ rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ {
+ /* cleanup activity */
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ return rc;
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
+ if ( rc != RC_OK )
+ {
+ /* cleanup activity */
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ /* trying to save last allocated cluster for future use */
+ fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
+ fat_buf_release(fs_info);
+ return rc;
+ }
+ }
+
+ save_cln = cl4find;
+ (*cls_added)++;
+
+ /* have we satisfied request ? */
+ if (*cls_added == count)
+ {
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = save_cln;
+ if (fs_info->vol.free_cls != 0xFFFFFFFF)
+ fs_info->vol.free_cls -= (*cls_added);
+ }
+ *last_cl = save_cln;
+ fat_buf_release(fs_info);
+ return rc;
+ }
+ }
+ i++;
+ cl4find++;
+ if (cl4find >= data_cls_val)
+ cl4find = 2;
+ }
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = save_cln;
+ if (fs_info->vol.free_cls != 0xFFFFFFFF)
+ fs_info->vol.free_cls -= (*cls_added);
+ }
+ *last_cl = save_cln;
+ fat_buf_release(fs_info);
+ return RC_OK;
+}
+
+/* fat_free_fat_clusters_chain --
+ * Free chain of clusters in Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * chain - number of the first cluster in the chain
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_free_fat_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 chain
+ )
+{
+ int rc = RC_OK, rc1 = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = chain;
+ unsigned32 next_cln = 0;
+ unsigned32 freed_cls_cnt = 0;
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);
+ if ( rc != RC_OK )
+ {
+ if ((fs_info->vol.type & FAT_FAT32) &&
+ (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))
+ fs_info->vol.free_cls += freed_cls_cnt;
+ fat_buf_release(fs_info);
+ return rc;
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);
+ if ( rc != RC_OK )
+ rc1 = rc;
+
+ freed_cls_cnt++;
+ cur_cln = next_cln;
+ }
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = chain;
+ if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
+ fs_info->vol.free_cls += freed_cls_cnt;
+ }
+
+ fat_buf_release(fs_info);
+ if (rc1 != RC_OK)
+ return rc1;
+
+ return RC_OK;
+}
+
+/* fat_get_fat_cluster --
+ * Fetches the contents of the cluster (link to next cluster in the chain)
+ * from Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to fetch the contents from
+ * ret_val - contents of the cluster 'cln' (link to next cluster in
+ * the chain)
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_get_fat_cluster(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 *ret_val
+ )
+{
+ int rc = RC_OK;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ bdbuf_buffer *block0 = NULL;
+ unsigned32 sec = 0;
+ unsigned32 ofs = 0;
+
+ /* sanity check */
+ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
+ set_errno_and_return_minus_one(EIO);
+
+ sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
+ fs_info->vol.afat_loc;
+ ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
+
+ rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ switch ( fs_info->vol.type )
+ {
+ case FAT_FAT12:
+ /*
+ * we are enforced in complex computations for FAT12 to escape CPU
+ * align problems for some architectures
+ */
+ *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;
+ }
+ else
+ {
+ *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;
+ }
+
+ if ( FAT_CLUSTER_IS_ODD(cln) )
+ *ret_val = (*ret_val) >> FAT12_SHIFT;
+ else
+ *ret_val = (*ret_val) & FAT_FAT12_MASK;
+
+ break;
+
+ case FAT_FAT16:
+ *ret_val = *((unsigned16 *)(block0->buffer + ofs));
+ *ret_val = CF_LE_W(*ret_val);
+ break;
+
+ case FAT_FAT32:
+ *ret_val = *((unsigned32 *)(block0->buffer + ofs));
+ *ret_val = CF_LE_L(*ret_val);
+ break;
+
+ default:
+ set_errno_and_return_minus_one(EIO);
+ break;
+ }
+
+ return RC_OK;
+}
+
+/* fat_set_fat_cluster --
+ * Set the contents of the cluster (link to next cluster in the chain)
+ * from Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to set contents to
+ * in_val - value to set
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_set_fat_cluster(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 in_val
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 ofs = 0;
+ unsigned16 fat16_clv = 0;
+ unsigned32 fat32_clv = 0;
+ bdbuf_buffer *block0 = NULL;
+
+ /* sanity check */
+ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
+ set_errno_and_return_minus_one(EIO);
+
+ sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
+ fs_info->vol.afat_loc;
+ ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
+
+ rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ switch ( fs_info->vol.type )
+ {
+ case FAT_FAT12:
+ if ( FAT_CLUSTER_IS_ODD(cln) )
+ {
+ fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) |
+ (unsigned8)(fat16_clv & 0x00FF);
+
+ fat_buf_mark_modified(fs_info);
+
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *((unsigned8 *)(block0->buffer)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+
+ fat_buf_mark_modified(fs_info);
+ }
+ else
+ {
+ *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer + ofs + 1)) =
+ (*((unsigned8 *)(block0->buffer + ofs + 1))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+ }
+ }
+ else
+ {
+ fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));
+
+ *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) |
+ (unsigned8)(fat16_clv & 0x00FF);
+
+ fat_buf_mark_modified(fs_info);
+
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) & 0xF0;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+
+ fat_buf_mark_modified(fs_info);
+ }
+ else
+ {
+ *((unsigned8 *)(block0->buffer + ofs + 1)) =
+ (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;
+
+ *((unsigned8 *)(block0->buffer + ofs+1)) =
+ (*((unsigned8 *)(block0->buffer + ofs+1))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+ }
+ }
+ break;
+
+ case FAT_FAT16:
+ *((unsigned16 *)(block0->buffer + ofs)) =
+ (unsigned16)(CT_LE_W(in_val));
+ fat_buf_mark_modified(fs_info);
+ break;
+
+ case FAT_FAT32:
+ fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
+
+ *((unsigned32 *)(block0->buffer + ofs)) =
+ (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
+
+ *((unsigned32 *)(block0->buffer + ofs)) =
+ fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));
+
+ fat_buf_mark_modified(fs_info);
+ break;
+
+ default:
+ set_errno_and_return_minus_one(EIO);
+ break;
+
+ }
+
+ return RC_OK;
+}
diff --git a/c/src/libfs/src/dosfs/fat_fat_operations.h b/c/src/libfs/src/dosfs/fat_fat_operations.h
new file mode 100644
index 0000000000..59b6a84018
--- /dev/null
+++ b/c/src/libfs/src/dosfs/fat_fat_operations.h
@@ -0,0 +1,58 @@
+/*
+ * fat_fat_operations.h
+ *
+ * Constants/data structures/prototypes for operations on Files Allocation
+ * Table
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_FAT_FAT_OPERATIONS_H__
+#define __DOSFS_FAT_FAT_OPERATIONS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <rtems/bdbuf.h>
+#include "fat.h"
+
+int
+fat_get_fat_cluster(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 *ret_val);
+
+int
+fat_set_fat_cluster(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 in_val);
+
+int
+fat_scan_fat_for_free_clusters(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 *chain,
+ unsigned32 count,
+ unsigned32 *cls_added,
+ unsigned32 *last_cl
+);
+
+int
+fat_free_fat_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 chain
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_FAT_OPERATIONS_H__ */
diff --git a/c/src/libfs/src/dosfs/fat_file.c b/c/src/libfs/src/dosfs/fat_file.c
new file mode 100644
index 0000000000..4fd8a5024f
--- /dev/null
+++ b/c/src/libfs/src/dosfs/fat_file.c
@@ -0,0 +1,979 @@
+/*
+ * fat_file.c
+ *
+ * General operations on "fat-file"
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ *
+ */
+
+#include <bsp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+static inline void
+_hash_insert(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el);
+
+static inline void
+_hash_delete(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el);
+
+static inline int
+_hash_search(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ Chain_Control *hash,
+ unsigned32 key1,
+ unsigned32 key2,
+ void **ret
+);
+
+static int
+fat_file_lseek(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 file_cln,
+ unsigned32 *disk_cln
+);
+
+/* fat_file_open --
+ * Open fat-file. Two hash tables are accessed by key
+ * constructed from cluster num and offset of the node (i.e.
+ * files/directories are distinguished by location on the disk).
+ * First, hash table("vhash") consists of fat-file descriptors corresponded
+ * to "valid" files is accessed. Search is made by 2 fields equal to key
+ * constructed. If descriptor is found in the "vhash" - return it.
+ * Otherwise search is made in hash table("rhash") consits of fat-file
+ * descriptors corresponded to "removed-but-still-open" files with the
+ * same keys.
+ * If search failed, new fat-file descriptor is added to "vhash"
+ * with both key fields equal to constructed key. Otherwise new fat-file
+ * descriptor is added to "vhash" with first key field equal to key
+ * constructed and the second equal to an unique (unique among all values
+ * of second key fields) value.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - cluster num of the node
+ * ofs - offset of the node
+ * fat_fd - placeholder for returned fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK and pointer to opened descriptor on success, or -1 if error
+ * occured (errno set appropriately)
+ */
+int
+fat_file_open(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 ofs,
+ fat_file_fd_t **fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *lfat_fd = NULL;
+ unsigned32 key = 0;
+
+ /* construct key */
+ key = fat_construct_key(mt_entry, cln, ofs);
+
+ /* access "valid" hash table */
+ rc = _hash_search(mt_entry, fs_info->vhash, key, 0, (void **)&lfat_fd);
+ if ( rc == RC_OK )
+ {
+ /* return pointer to fat_file_descriptor allocated before */
+ (*fat_fd) = lfat_fd;
+ lfat_fd->links_num++;
+ return rc;
+ }
+
+ /* access "removed-but-still-open" hash table */
+ rc = _hash_search(mt_entry, fs_info->rhash, key, key, (void **)&lfat_fd);
+
+ lfat_fd = (*fat_fd) = (fat_file_fd_t*)malloc(sizeof(fat_file_fd_t));
+ if ( lfat_fd == NULL )
+ set_errno_and_return_minus_one( ENOMEM );
+
+ lfat_fd->links_num = 1;
+ lfat_fd->flags &= ~FAT_FILE_REMOVED;
+ lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+
+ if ( rc != RC_OK )
+ lfat_fd->ino = key;
+ else
+ {
+ lfat_fd->ino = fat_get_unique_ino(mt_entry);
+
+ if ( lfat_fd->ino == 0 )
+ {
+ free((*fat_fd));
+ /*
+ * XXX: kernel resource is unsufficient, but not the memory,
+ * but there is no suitable errno :(
+ */
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ }
+ _hash_insert(fs_info->vhash, key, lfat_fd->ino, lfat_fd);
+
+
+ /*
+ * other fields of fat-file descriptor will be initialized on upper
+ * level
+ */
+
+ return RC_OK;
+}
+
+
+/* fat_file_reopen --
+ * Increment by 1 number of links
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK
+ */
+int
+fat_file_reopen(fat_file_fd_t *fat_fd)
+{
+ fat_fd->links_num++;
+ return RC_OK;
+}
+
+/* fat_file_close --
+ * Close fat-file. If count of links to fat-file
+ * descriptor is greater than 1 (i.e. somebody esle holds pointer
+ * to this descriptor) just decrement it. Otherwise
+ * do the following. If this descriptor corresponded to removed fat-file
+ * then free clusters contained fat-file data, delete descriptor from
+ * "rhash" table and free memory allocated by descriptor. If descriptor
+ * correspondes to non-removed fat-file and 'ino' field has value from
+ * unique inode numbers pool then set count of links to descriptor to zero
+ * and leave it in hash, otherwise delete descriptor from "vhash" and free
+ * memory allocated by the descriptor
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_close(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 key = 0;
+
+ /*
+ * if links_num field of fat-file descriptor is greater than 1
+ * decrement the count of links and return
+ */
+ if (fat_fd->links_num > 1)
+ {
+ fat_fd->links_num--;
+ return rc;
+ }
+
+ key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs);
+
+ if (fat_fd->flags & FAT_FILE_REMOVED)
+ {
+ rc = fat_file_truncate(mt_entry, fat_fd, 0);
+ if ( rc != RC_OK )
+ return rc;
+
+ _hash_delete(fs_info->rhash, key, fat_fd->ino, fat_fd);
+
+ if ( fat_ino_is_unique(mt_entry, fat_fd->ino) )
+ fat_free_unique_ino(mt_entry, fat_fd->ino);
+
+ free(fat_fd);
+ }
+ else
+ {
+ if (fat_ino_is_unique(mt_entry, fat_fd->ino))
+ {
+ fat_fd->links_num = 0;
+ }
+ else
+ {
+ _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
+ free(fat_fd);
+ }
+ }
+ return rc;
+}
+
+/* fat_file_read --
+ * Read 'count' bytes from 'start' position from fat-file. This
+ * interface hides the architecture of fat-file, represents it as
+ * linear file
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * start - offset in fat-file (in bytes) to read from
+ * count - count of bytes to read
+ * buf - buffer provided by user
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno
+ * set appropriately)
+ */
+ssize_t
+fat_file_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cmpltd = 0;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 save_cln = 0;
+ unsigned32 ofs = 0;
+ unsigned32 save_ofs;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+ unsigned32 c = 0;
+
+ /* it couldn't be removed - otherwise cache update will be broken */
+ if (count == 0)
+ return cmpltd;
+
+ /*
+ * >= because start is offset and computed from 0 and file_size
+ * computed from 1
+ */
+ if ( start >= fat_fd->fat_file_size )
+ return FAT_EOF;
+
+ if ((count > fat_fd->fat_file_size) ||
+ (start > fat_fd->fat_file_size - count))
+ count = fat_fd->fat_file_size - start;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
+ sec += (start >> fs_info->vol.sec_log2);
+ byte = start & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_read(mt_entry, sec, byte, count, buf);
+ if ( ret < 0 )
+ return -1;
+
+ return ret;
+ }
+
+ cl_start = start >> fs_info->vol.bpc_log2;
+ save_ofs = ofs = start & (fs_info->vol.bpc - 1);
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ while (count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bpc - ofs));
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ sec += (ofs >> fs_info->vol.sec_log2);
+ byte = ofs & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_read(mt_entry, sec, byte, c, buf + cmpltd);
+ if ( ret < 0 )
+ return -1;
+
+ count -= c;
+ cmpltd += c;
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ ofs = 0;
+ }
+
+ /* update cache */
+ /* XXX: check this - I'm not sure :( */
+ fat_fd->map.file_cln = cl_start +
+ ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
+ fat_fd->map.disk_cln = save_cln;
+
+ return cmpltd;
+}
+
+/* fat_file_write --
+ * Write 'count' bytes of data from user supplied buffer to fat-file
+ * starting at offset 'start'. This interface hides the architecture
+ * of fat-file, represents it as linear file
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * start - offset(in bytes) to write from
+ * count - count
+ * buf - buffer provided by user
+ *
+ * RETURNS:
+ * number of bytes actually written to the file on success, or -1 if
+ * error occured (errno set appropriately)
+ */
+ssize_t
+fat_file_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf
+ )
+{
+ int rc = 0;
+ ssize_t ret = 0;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cmpltd = 0;
+ unsigned32 cur_cln = 0;
+ unsigned32 save_cln;
+ unsigned32 cl_start = 0;
+ unsigned32 ofs = 0;
+ unsigned32 save_ofs;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+ unsigned32 c = 0;
+
+ if ( count == 0 )
+ return cmpltd;
+
+ if ( start > fat_fd->fat_file_size )
+ set_errno_and_return_minus_one( EIO );
+
+ if ((count > fat_fd->size_limit) ||
+ (start > fat_fd->size_limit - count))
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_extend(mt_entry, fat_fd, start + count, &c);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * check whether there was enough room on device to locate
+ * file of 'start + count' bytes
+ */
+ if (c != (start + count))
+ count = c - start;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
+ sec += (start >> fs_info->vol.sec_log2);
+ byte = start & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_write(mt_entry, sec, byte, count, buf);
+ if ( ret < 0 )
+ return -1;
+
+ return ret;
+ }
+
+ cl_start = start >> fs_info->vol.bpc_log2;
+ save_ofs = ofs = start & (fs_info->vol.bpc - 1);
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ while (count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bpc - ofs));
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ sec += (ofs >> fs_info->vol.sec_log2);
+ byte = ofs & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_write(mt_entry, sec, byte, c, buf + cmpltd);
+ if ( ret < 0 )
+ return -1;
+
+ count -= c;
+ cmpltd += c;
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ ofs = 0;
+ }
+
+ /* update cache */
+ /* XXX: check this - I'm not sure :( */
+ fat_fd->map.file_cln = cl_start +
+ ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
+ fat_fd->map.disk_cln = save_cln;
+
+ return cmpltd;
+}
+
+/* fat_file_extend --
+ * Extend fat-file. If new length less than current fat-file size -
+ * do nothing. Otherwise calculate necessary count of clusters to add,
+ * allocate it and add new clusters chain to the end of
+ * existing clusters chain.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * new_length - new length
+ * a_length - placeholder for result - actual new length of file
+ *
+ * RETURNS:
+ * RC_OK and new length of file on success, or -1 if error occured (errno
+ * set appropriately)
+ */
+int
+fat_file_extend(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length,
+ unsigned32 *a_length
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 chain = 0;
+ unsigned32 bytes2add = 0;
+ unsigned32 cls2add = 0;
+ unsigned32 old_last_cl;
+ unsigned32 last_cl = 0;
+ unsigned32 bytes_remain = 0;
+ unsigned32 cls_added;
+
+ *a_length = new_length;
+
+ if (new_length <= fat_fd->fat_file_size)
+ return RC_OK;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ set_errno_and_return_minus_one( ENOSPC );
+
+ bytes_remain = (fs_info->vol.bpc -
+ (fat_fd->fat_file_size & (fs_info->vol.bpc - 1))) &
+ (fs_info->vol.bpc - 1);
+
+ bytes2add = new_length - fat_fd->fat_file_size;
+
+ if (bytes2add > bytes_remain)
+ bytes2add -= bytes_remain;
+ else
+ bytes2add = 0;
+
+ /*
+ * if in last cluster allocated for the file there is enough room to
+ * handle extention (hence we don't need to add even one cluster to the
+ * file ) - return
+ */
+ if (bytes2add == 0)
+ return RC_OK;
+
+ cls2add = ((bytes2add - 1) >> fs_info->vol.bpc_log2) + 1;
+
+ rc = fat_scan_fat_for_free_clusters(mt_entry, &chain, cls2add,
+ &cls_added, &last_cl);
+
+ /* this means that low level I/O error occured */
+ if (rc != RC_OK)
+ return rc;
+
+ /* this means that no space left on device */
+ if ((cls_added == 0) && (bytes_remain == 0))
+ set_errno_and_return_minus_one(ENOSPC);
+
+ /* check wether we satisfied request for 'cls2add' clusters */
+ if (cls2add != cls_added)
+ *a_length = new_length -
+ ((cls2add - cls_added - 1) << fs_info->vol.bpc_log2) -
+ (bytes2add & (fs_info->vol.bpc - 1));
+
+ /* add new chain to the end of existed */
+ if ( fat_fd->fat_file_size == 0 )
+ {
+ fat_fd->map.disk_cln = fat_fd->cln = chain;
+ fat_fd->map.file_cln = 0;
+ }
+ else
+ {
+ if (fat_fd->map.last_cln != FAT_UNDEFINED_VALUE)
+ {
+ old_last_cl = fat_fd->map.last_cln;
+ }
+ else
+ {
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ (fat_fd->fat_file_size - 1), &old_last_cl);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, old_last_cl, chain);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ fat_buf_release(fs_info);
+ }
+
+ /* update number of the last cluster of the file if it changed */
+ if (cls_added != 0)
+ {
+ fat_fd->map.last_cln = last_cl;
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ {
+ rc = fat_init_clusters_chain(mt_entry, chain);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ }
+ }
+
+ return RC_OK;
+}
+
+/* fat_file_truncate --
+ * Truncate fat-file. If new length greater than current fat-file size -
+ * do nothing. Otherwise find first cluster to free and free all clusters
+ * in the chain starting from this cluster.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * new_length - new length
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_truncate(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 new_last_cln = FAT_UNDEFINED_VALUE;
+
+
+ if ( new_length >= fat_fd->fat_file_size )
+ return rc;
+
+ assert(fat_fd->fat_file_size);
+
+ cl_start = (new_length + fs_info->vol.bpc - 1) >> fs_info->vol.bpc_log2;
+
+ if ((cl_start << fs_info->vol.bpc_log2) >= fat_fd->fat_file_size)
+ return RC_OK;
+
+ if (cl_start != 0)
+ {
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start - 1, &new_last_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ }
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ rc = fat_free_fat_clusters_chain(mt_entry, cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ if (cl_start != 0)
+ {
+ rc = fat_set_fat_cluster(mt_entry, new_last_cln, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ return rc;
+ fat_fd->map.file_cln = cl_start - 1;
+ fat_fd->map.disk_cln = new_last_cln;
+ fat_fd->map.last_cln = new_last_cln;
+ }
+ return RC_OK;
+}
+
+/* fat_file_ioctl --
+ * F_CLU_NUM:
+ * make mapping between serial number of the cluster in fat-file and
+ * its real number on the volume
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ * mt_entry - mount table entry
+ * cmd - command
+ * ...
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured and errno set appropriately
+ */
+int
+fat_file_ioctl(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ int cmd,
+ ...)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 pos = 0;
+ unsigned32 *ret;
+ va_list ap;
+
+ va_start(ap, cmd);
+
+ switch (cmd)
+ {
+ case F_CLU_NUM:
+ pos = va_arg(ap, int);
+ ret = va_arg(ap, int *);
+
+ /* sanity check */
+ if ( pos >= fat_fd->fat_file_size )
+ set_errno_and_return_minus_one( EIO );
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ /* cluster 0 (zero) reserved for root dir */
+ *ret = 0;
+ return RC_OK;
+ }
+
+ cl_start = pos >> fs_info->vol.bpc_log2;
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ *ret = cur_cln;
+ break;
+
+ default:
+ errno = EINVAL;
+ rc = -1;
+ break;
+ }
+ return rc;
+}
+
+/* fat_file_mark_removed --
+ * Remove the fat-file descriptor from "valid" hash table, insert it
+ * into "removed-but-still-open" hash table and set up "removed" bit.
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * None
+ */
+void
+fat_file_mark_removed(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 key = 0;
+
+ key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs);
+
+ _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
+
+ _hash_insert(fs_info->rhash, key, fat_fd->ino, fat_fd);
+
+ fat_fd->flags |= FAT_FILE_REMOVED;
+}
+
+/* fat_file_datasync --
+ * Synchronize fat-file - flush all buffered data to the media.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured and errno set appropriately
+ */
+int
+fat_file_datasync(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = fat_fd->cln;
+ bdbuf_buffer *block = NULL;
+ unsigned32 sec = 0;
+ unsigned32 i = 0;
+
+ if (fat_fd->fat_file_size == 0)
+ return RC_OK;
+
+ /*
+ * we can use only one bdbuf :( and we also know that cache is useless
+ * for sync operation, so don't use it
+ */
+ rc = fat_buf_release(fs_info);
+ if (rc != RC_OK)
+ return rc;
+
+ /* for each cluster of the file ... */
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ /* for each sector in cluster ... */
+ for ( i = 0; i < fs_info->vol.spc; i++ )
+ {
+ /* ... sync it */
+ sc = rtems_bdbuf_read(fs_info->vol.dev, (sec + i), &block);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ sc = rtems_bdbuf_sync(block);
+ if ( sc != RTEMS_SUCCESSFUL )
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+ }
+ return rc;
+}
+
+/* fat_file_size --
+ * Calculate fat-file size - fat-file is nothing that clusters chain, so
+ * go through all clusters in the chain and count it. Only
+ * special case is root directory for FAT12/16 volumes.
+ * This function is used only for directories which are fat-files with
+ * non-zero length, hence 'fat_fd->cln' always contains valid data.
+ * Calculated size is stored in 'fat_file_size' field of fat-file
+ * descriptor.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = fat_fd->cln;
+ unsigned32 save_cln = 0;
+
+ /* Have we requested root dir size for FAT12/16? */
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ fat_fd->fat_file_size = fs_info->vol.rdir_size;
+ return rc;
+ }
+
+ fat_fd->fat_file_size = 0;
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ fat_fd->fat_file_size += fs_info->vol.bpc;
+ }
+ fat_fd->map.last_cln = save_cln;
+ return rc;
+}
+
+/* hash support routines */
+
+/* _hash_insert --
+ * Insert elemnt into hash based on key 'key1'
+ *
+ * PARAMETERS:
+ * hash - hash element will be inserted into
+ * key1 - key on which insertion is based on
+ * key2 - not used during insertion
+ * el - element to insert
+ *
+ * RETURNS:
+ * None
+ */
+static inline void
+_hash_insert(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el)
+{
+ _Chain_Append((hash) + ((key1) % FAT_HASH_MODULE), &(el)->link);
+}
+
+
+/* _hash_delete --
+ * Remove element from hash
+ *
+ * PARAMETERS:
+ * hash - hash element will be removed from
+ * key1 - not used
+ * key2 - not used
+ * el - element to delete
+ *
+ * RETURNS:
+ * None
+ */
+static inline void
+_hash_delete(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el)
+{
+ _Chain_Extract(&(el)->link);
+}
+
+/* _hash_search --
+ * Search element in hash. If both keys match pointer to found element
+ * is returned
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * hash - hash element will be removed from
+ * key1 - search key
+ * key2 - search key
+ * ret - placeholder for result
+ *
+ * RETURNS:
+ * 0 and pointer to found element on success, -1 otherwise
+ */
+static inline int
+_hash_search(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ Chain_Control *hash,
+ unsigned32 key1,
+ unsigned32 key2,
+ void **ret
+ )
+{
+ unsigned32 mod = (key1) % FAT_HASH_MODULE;
+ Chain_Node *the_node = ((Chain_Control *)((hash) + mod))->first;
+
+ for ( ; !_Chain_Is_tail((hash) + mod, the_node) ; )
+ {
+ fat_file_fd_t *ffd = (fat_file_fd_t *)the_node;
+ unsigned32 ck =
+ fat_construct_key(mt_entry, ffd->info_cln, ffd->info_ofs);
+
+ if ( (key1) == ck)
+ {
+ if ( ((key2) == 0) || ((key2) == ffd->ino) )
+ {
+ *ret = (void *)the_node;
+ return 0;
+ }
+ }
+ the_node = the_node->next;
+ }
+ return -1;
+}
+
+static int
+fat_file_lseek(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 file_cln,
+ unsigned32 *disk_cln
+ )
+{
+ int rc = RC_OK;
+/*
+ assert(fat_fd->fat_file_size);
+ */
+ if (file_cln == fat_fd->map.file_cln)
+ *disk_cln = fat_fd->map.disk_cln;
+ else
+ {
+ unsigned32 cur_cln;
+ unsigned32 count;
+ unsigned32 i;
+
+ if (file_cln > fat_fd->map.file_cln)
+ {
+ cur_cln = fat_fd->map.disk_cln;
+ count = file_cln - fat_fd->map.file_cln;
+ }
+ else
+ {
+ cur_cln = fat_fd->cln;
+ count = file_cln;
+ }
+
+ /* skip over the clusters */
+ for (i = 0; i < count; i++)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+ }
+
+ /* update cache */
+ fat_fd->map.file_cln = file_cln;
+ fat_fd->map.disk_cln = cur_cln;
+
+ *disk_cln = cur_cln;
+ }
+ return RC_OK;
+}
diff --git a/c/src/libfs/src/dosfs/fat_file.h b/c/src/libfs/src/dosfs/fat_file.h
new file mode 100644
index 0000000000..2821a27cf7
--- /dev/null
+++ b/c/src/libfs/src/dosfs/fat_file.h
@@ -0,0 +1,195 @@
+/*
+ * fat_file.h
+ *
+ * Constants/data structures/prototypes for operations on "fat-file"
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_FAT_FILE_H__
+#define __DOSFS_FAT_FILE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <time.h>
+
+/* "fat-file" representation
+ *
+ * the idea is: fat-file is nothing but a cluster chain, any open fat-file is
+ * represented in system by fat-file descriptor and has well-known
+ * file interface:
+ *
+ * fat_file_open()
+ * fat_file_close()
+ * fat_file_read()
+ * fat_file_write()
+ *
+ * Such interface hides the architecture of fat-file and represents it like
+ * linear file
+ */
+
+typedef rtems_filesystem_node_types_t fat_file_type_t;
+
+#define FAT_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define FAT_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+typedef struct fat_file_map_s
+{
+ unsigned32 file_cln;
+ unsigned32 disk_cln;
+ unsigned32 last_cln;
+} fat_file_map_t;
+/*
+ * descriptor of a fat-file
+ *
+ * To each particular clusters chain
+ */
+typedef struct fat_file_fd_s
+{
+ Chain_Node link; /*
+ * fat-file descriptors organized into hash;
+ * collision lists are handled via link
+ * field
+ */
+ unsigned32 links_num; /*
+ * the number of fat_file_open call on
+ * this fat-file
+ */
+ unsigned32 ino; /* inode, file serial number :)))) */
+ fat_file_type_t fat_file_type;
+ unsigned32 size_limit;
+ unsigned32 fat_file_size; /* length */
+ unsigned32 info_cln;
+ unsigned32 cln;
+ unsigned16 info_ofs;
+ unsigned char first_char;
+ unsigned8 flags;
+ fat_file_map_t map;
+ time_t mtime;
+
+} fat_file_fd_t;
+
+
+#define FAT_FILE_REMOVED 0x01
+
+#define FAT_FILE_IS_REMOVED(p)\
+ (((p)->flags & FAT_FILE_REMOVED) ? 1 : 0)
+
+/* ioctl macros */
+#define F_CLU_NUM 0x01
+
+/*
+ * Each file and directory on a MSDOS volume is unique identified by it
+ * location, i.e. location of it 32 Bytes Directory Entry Structure. We can
+ * distinguish them by cluster number it locates on and offset inside this
+ * cluster. But root directory on any volumes (FAT12/16/32) has no 32 Bytes
+ * Directory Entry Structure corresponded to it. So we assume 32 Bytes
+ * Directory Entry Structure of root directory locates at cluster 1 (invalid
+ * cluaster number) and offset 0
+ */
+#define FAT_ROOTDIR_CLUSTER_NUM 0x01
+
+#define FAT_FD_OF_ROOT_DIR(fat_fd) \
+ ((fat_fd->info_cln == FAT_ROOTDIR_CLUSTER_NUM ) && \
+ (fat_fd->info_ofs == 0))
+
+#define FAT_EOF 0x00
+
+/* fat_construct_key --
+ * Construct key for hash access: convert (cluster num, offset) to
+ * (sector512 num, new offset) and than construct key as
+ * key = (sector512 num) << 4 | (new offset)
+ *
+ * PARAMETERS:
+ * cl - cluster number
+ * ofs - offset inside cluster 'cl'
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * constructed key
+ */
+static inline unsigned32
+fat_construct_key(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs)
+{
+ return ( ((fat_cluster_num_to_sector512_num(mt_entry, cl) +
+ (ofs >> FAT_SECTOR512_BITS)) << 4) +
+ ((ofs >> 5) & (FAT_DIRENTRIES_PER_SEC512 - 1)) );
+}
+
+/* Prototypes for "fat-file" operations */
+int
+fat_file_open(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 ofs,
+ fat_file_fd_t **fat_fd);
+
+int
+fat_file_reopen(fat_file_fd_t *fat_fd);
+
+int
+fat_file_close(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+ssize_t
+fat_file_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf);
+
+ssize_t
+fat_file_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf);
+
+int
+fat_file_extend(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length,
+ unsigned32 *a_length);
+
+int
+fat_file_truncate(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length);
+
+int
+fat_file_datasync(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+
+int
+fat_file_ioctl(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ int cmd,
+ ...);
+
+int
+fat_file_size(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+void
+fat_file_mark_removed(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_FILE_H__ */
diff --git a/c/src/libfs/src/dosfs/msdos.h b/c/src/libfs/src/dosfs/msdos.h
new file mode 100644
index 0000000000..a9216b1ed3
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos.h
@@ -0,0 +1,408 @@
+/*
+ * msdos.h
+ *
+ * The MSDOS filesystem constants/data structures/prototypes
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_MSDOS_H__
+#define __DOSFS_MSDOS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_file.h"
+
+#ifndef RC_OK
+#define RC_OK 0x00000000
+#endif
+
+#define MSDOS_NAME_NOT_FOUND_ERR 0xDD000001
+
+/*
+ * This structure identifies the instance of the filesystem on the MSDOS
+ * level.
+ */
+typedef struct msdos_fs_info_s
+{
+ fat_fs_info_t fat; /*
+ * volume
+ * description
+ */
+ rtems_filesystem_file_handlers_r *directory_handlers; /*
+ * a set of routines
+ * that handles the
+ * nodes of directory
+ * type
+ */
+ rtems_filesystem_file_handlers_r *file_handlers; /*
+ * a set of routines
+ * that handles the
+ * nodes of file
+ * type
+ */
+ rtems_id vol_sema; /*
+ * semaphore
+ * associated with
+ * the volume
+ */
+ unsigned8 *cl_buf; /*
+ * just placeholder
+ * for anything
+ */
+} msdos_fs_info_t;
+
+/* a set of routines that handle the nodes which are directories */
+extern rtems_filesystem_file_handlers_r msdos_dir_handlers;
+
+/* a set of routines that handle the nodes which are files */
+extern rtems_filesystem_file_handlers_r msdos_file_handlers;
+
+/* Volume semaphore timeout value */
+#define MSDOS_VOLUME_SEMAPHORE_TIMEOUT 100
+
+/* Node types */
+#define MSDOS_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define MSDOS_REGULAR_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+typedef rtems_filesystem_node_types_t msdos_node_type_t;
+
+/*
+ * Macros for fetching fields from 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE 32 /* 32 bytes */
+
+#define MSDOS_DIR_NAME(x) (unsigned8 *)((x) + 0)
+#define MSDOS_DIR_ATTR(x) (unsigned8 *)((x) + 11)
+#define MSDOS_DIR_NT_RES(x) (unsigned8 *)((x) + 12)
+#define MSDOS_DIR_CRT_TIME_TENTH(x) (unsigned8 *)((x) + 13)
+#define MSDOS_DIR_CRT_TIME(x) (unsigned16 *)((x) + 14)
+#define MSDOS_DIR_CRT_DATE(x) (unsigned16 *)((x) + 16)
+#define MSDOS_DIR_LAST_ACCESS_DATE(x) (unsigned16 *)((x) + 18)
+#define MSDOS_DIR_FIRST_CLUSTER_HI(x) (unsigned16 *)((x) + 20)
+#define MSDOS_DIR_WRITE_TIME(x) (unsigned16 *)((x) + 22)
+#define MSDOS_DIR_WRITE_DATE(x) (unsigned16 *)((x) + 24)
+#define MSDOS_DIR_FIRST_CLUSTER_LOW(x) (unsigned16 *)((x) + 26)
+#define MSDOS_DIR_FILE_SIZE(x) (unsigned32 *)((x) + 28)
+
+#define MSDOS_EXTRACT_CLUSTER_NUM(p) \
+ (unsigned32)( (CF_LE_W(*MSDOS_DIR_FIRST_CLUSTER_LOW(p))) | \
+ ((CF_LE_W((*MSDOS_DIR_FIRST_CLUSTER_HI(p))))<<16) )
+
+/*
+ * Fields offset in 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_FILE_SIZE_OFFSET 28
+#define MSDOS_FILE_NAME_OFFSET 0
+#define MSDOS_FIRST_CLUSTER_HI_OFFSET 20
+#define MSDOS_FIRST_CLUSTER_LOW_OFFSET 26
+#define MSDOS_FILE_WDATE_OFFSET 24
+#define MSDOS_FILE_WTIME_OFFSET 22
+
+/*
+ * Possible values of DIR_Attr field of 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_ATTR_READ_ONLY 0x01
+#define MSDOS_ATTR_HIDDEN 0x02
+#define MSDOS_ATTR_SYSTEM 0x04
+#define MSDOS_ATTR_VOLUME_ID 0x08
+#define MSDOS_ATTR_DIRECTORY 0x10
+#define MSDOS_ATTR_ARCHIVE 0x20
+
+/*
+ * Possible values of DIR_Name[0] field of 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_THIS_DIR_ENTRY_EMPTY 0xE5
+#define MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY 0x00
+
+
+/*
+ * Macros for names parsing and formatting
+ */
+#define msdos_is_valid_name_char(_ch) (1)
+#define msdos_is_separator(_ch) rtems_filesystem_is_separator(_ch)
+
+#define MSDOS_SHORT_NAME_LEN 11 /* 11 characters */
+#define MSDOS_NAME_MAX MSDOS_SHORT_NAME_LEN
+#define MSDOS_NAME_MAX_WITH_DOT (MSDOS_NAME_MAX + 1)
+
+#define MSDOS_DOT_NAME ". " /* ".", padded to MSDOS_NAME chars */
+#define MSDOS_DOTDOT_NAME ".. " /* "..", padded to MSDOS_NAME chars */
+
+typedef enum msdos_token_types_e
+{
+ MSDOS_NO_MORE_PATH,
+ MSDOS_CURRENT_DIR,
+ MSDOS_UP_DIR,
+ MSDOS_NAME,
+ MSDOS_INVALID_TOKEN
+} msdos_token_types_t;
+
+/* Others macros */
+#define MSDOS_RES_NT_VALUE 0x00
+#define MSDOS_INIT_DIR_SIZE 0x00
+
+/* "dot" entry offset in a directory */
+#define MSDOS_DOT_DIR_ENTRY_OFFSET 0x00 /* first entry in directory */
+
+/* "dotdot" entry offset in a directory */
+#define MSDOS_DOTDOT_DIR_ENTRY_OFFSET 0x20 /* second entry in directory */
+
+/* 'p' should be char* */
+#define DOT_NODE_P(p) ((char *)(p))
+#define DOTDOT_NODE_P(p) ((char *)((p) + MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE))
+
+/* Size limits for files and directories (see M$ White Paper) */
+#define MSDOS_MAX_DIR_LENGHT 0x200000 /* 2,097,152 bytes */
+#define MSDOS_MAX_FILE_SIZE 0xFFFFFFFF /* 4 Gb */
+
+/*
+ * The number of 32 bytes long FAT Directory Entry
+ * Structures per 512 bytes sector
+ */
+#define MSDOS_DPS512_NUM 16
+
+/* Prototypes */
+int
+msdos_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+int
+msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+int
+msdos_eval_path(const char *pathname, /* IN */
+ int flags, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */);
+
+int
+msdos_eval4make(const char *path, /* IN */
+ rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
+ const char **name /* OUT */);
+
+int
+msdos_unlink(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_free_node_info(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+rtems_filesystem_node_types_t
+msdos_node_type(rtems_filesystem_location_info_t *pathloc);
+
+int
+msdos_mknod(const char *path, /* IN */
+ mode_t mode, /* IN */
+ dev_t dev, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */);
+
+int
+msdos_utime(rtems_filesystem_location_info_t *pathloc, /* IN */
+ time_t actime, /* IN */
+ time_t modtime /* IN */);
+
+int
+msdos_initialize_support(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry,
+ rtems_filesystem_operations_table *op_table,
+ rtems_filesystem_file_handlers_r *file_handlers,
+ rtems_filesystem_file_handlers_r *directory_handlers
+);
+
+int
+msdos_file_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+
+int
+msdos_file_close(rtems_libio_t *iop /* IN */);
+
+ssize_t
+msdos_file_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+ssize_t
+msdos_file_write(
+ rtems_libio_t *iop, /* IN */
+ const void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+int
+msdos_file_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+
+int
+msdos_file_stat(rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */);
+
+int
+msdos_file_ftruncate(
+ rtems_libio_t *iop, /* IN */
+ off_t length /* IN */
+);
+
+int
+msdos_file_sync(rtems_libio_t *iop);
+
+int
+msdos_file_datasync(rtems_libio_t *iop);
+
+int
+msdos_file_ioctl(
+ rtems_libio_t *iop, /* IN */
+ unsigned32 command, /* IN */
+ void *buffer /* IN */
+);
+
+int
+msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_dir_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+
+int
+msdos_dir_close(rtems_libio_t *iop /* IN */);
+
+ssize_t
+msdos_dir_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+int
+msdos_dir_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+
+int
+msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_dir_sync(rtems_libio_t *iop);
+
+int
+msdos_dir_stat(
+ rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */
+);
+
+int
+msdos_creat_node(rtems_filesystem_location_info_t *parent_loc,
+ msdos_node_type_t type,
+ char *name,
+ mode_t mode);
+
+/* Misc prototypes */
+msdos_token_types_t msdos_get_token(const char *path,
+ char *token,
+ int *token_len);
+
+int
+msdos_find_name(rtems_filesystem_location_info_t *parent_loc,
+ char *name);
+
+int
+msdos_get_name_node(rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry);
+
+int
+msdos_dir_info_remove(rtems_filesystem_location_info_t *pathloc);
+
+void
+msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date);
+
+unsigned int
+msdos_date_dos2unix(unsigned short time_val, unsigned short date);
+
+int
+msdos_set_first_cluster_num(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+int
+msdos_set_file_size(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+int
+msdos_set_first_char4file_name(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char first_char);
+
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+);
+
+
+int
+msdos_dir_is_empty(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val);
+
+int
+msdos_find_name_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry);
+
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+);
+
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_MSDOS_H__ */
diff --git a/c/src/libfs/src/dosfs/msdos_create.c b/c/src/libfs/src/dosfs/msdos_create.c
new file mode 100644
index 0000000000..4b4c7001ca
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_create.c
@@ -0,0 +1,208 @@
+/*
+ * Routine to create a new MSDOS filesystem node
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ *
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtems/libio_.h>
+#include <time.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_creat_node --
+ * Create a new node. If a new node is file, FAT 32 Bytes Directory
+ * Entry Structure (see M$ White Paper) is initialized, free space is
+ * found in parent directory and structure is written to the disk.
+ * In case of directory, all above steps present and also new cluster
+ * is allocated for a new directory and dot and dotdot nodes are created
+ * in alloceted cluster.
+ *
+ * PARAMETERS:
+ * parent_loc - parent (directory we are going to create node in)
+ * type - new node type (file or directory)
+ * name - new node name
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ *
+ */
+int
+msdos_creat_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ msdos_node_type_t type,
+ char *name,
+ mode_t mode
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *parent_fat_fd = parent_loc->node_access;
+ fat_file_fd_t *fat_fd = NULL;
+ time_t time_ret = 0;
+ unsigned16 time_val = 0;
+ unsigned16 date = 0;
+ fat_auxiliary_t aux;
+ unsigned char new_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
+
+ memset(new_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
+
+ /* set up name */
+ strncpy(MSDOS_DIR_NAME(new_node), name, MSDOS_NAME_MAX);
+
+ /* fill reserved field */
+ *MSDOS_DIR_NT_RES(new_node) = MSDOS_RES_NT_VALUE;
+
+ /* set up last write date and time */
+ time_ret = time(NULL);
+ if ( time_ret == -1 )
+ return -1;
+
+ msdos_date_unix2dos(time_ret, &time_val, &date);
+ *MSDOS_DIR_WRITE_TIME(new_node) = CT_LE_W(time_val);
+ *MSDOS_DIR_WRITE_DATE(new_node) = CT_LE_W(date);
+
+ /* initialize directory/file size */
+ *MSDOS_DIR_FILE_SIZE(new_node) = MSDOS_INIT_DIR_SIZE;
+
+ if (type == MSDOS_DIRECTORY)
+ *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_DIRECTORY;
+ else
+ *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE;
+
+ /*
+ * find free space in the parent directory and write new initialized
+ * FAT 32 Bytes Directory Entry Structure (see M$ White Paper)
+ * to the disk
+ */
+ rc = msdos_get_name_node(parent_loc, NULL, &aux, new_node);
+ if ( rc != RC_OK )
+ return rc;
+
+ /*
+ * if we create a new file we are done, if directory there are more steps
+ * to do
+ */
+ if (type == MSDOS_DIRECTORY)
+ {
+ /* open new directory as fat-file */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ /*
+ * we opened fat-file for node we just created, so initialize fat-file
+ * descritor
+ */
+ fat_fd->info_cln = aux.cln;
+ fat_fd->info_ofs = aux.ofs;
+ fat_fd->fat_file_size = 0;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ /*
+ * dot and dotdot entries are identical to new node except the
+ * names
+ */
+ memcpy(DOT_NODE_P(dot_dotdot), new_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memcpy(DOTDOT_NODE_P(dot_dotdot), new_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
+ MSDOS_NAME_MAX);
+ memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
+ MSDOS_NAME_MAX);
+
+ /* set up cluster num for dotdot entry */
+ /*
+ * here we can ommit FAT32 condition because for all FAT types dirs
+ * right under root dir should contain 0 in dotdot entry but for
+ * FAT12/16 parent_fat_fd->cluster_num always contains such value
+ */
+ if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
+ (fs_info->fat.vol.type & FAT_FAT32))
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ }
+ else
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)((parent_fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
+ }
+
+ /*
+ * write dot and dotdot entries to new fat-file: currently fat-file
+ * correspondes to a new node is zero length, so it will be extended
+ * by one cluster and entries will be written
+ */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
+ dot_dotdot);
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* increment fat-file size by cluster size */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* set up cluster num for dot entry */
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)((fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)(((fat_fd->cln) & 0xFFFF0000) >> 16));
+
+ /* rewrite dot entry */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ DOT_NODE_P(dot_dotdot));
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* write first cluster num of a new directory to disk */
+ rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto error;
+
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ }
+ return RC_OK;
+
+error:
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+
+err:
+ /* mark 32bytes structure on the disk as free */
+ msdos_set_first_char4file_name(parent_loc->mt_entry, aux.cln, aux.ofs,
+ 0xE5);
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_dir.c b/c/src/libfs/src/dosfs/msdos_dir.c
new file mode 100644
index 0000000000..93449cd2fb
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_dir.c
@@ -0,0 +1,483 @@
+/*
+ * MSDOS directory handlers implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <rtems/libio_.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_dir_open --
+ * Open fat-file which correspondes to the directory being opened and
+ * set offset field of file control block to zero.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * pathname - name
+ * flag - flags
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK, if directory opened successfully, or -1 if error occured (errno
+ * set apropriately)
+ */
+int
+msdos_dir_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
+ unsigned32 mode)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ iop->offset = 0;
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_close --
+ * Close fat-file which correspondes to the directory being closed
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK, if directory closed successfully, or -1 if error occured (errno
+ * set apropriately.
+ */
+int
+msdos_dir_close(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_read --
+ * 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.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - buffer provided by user
+ * count - count of bytes to read
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+ssize_t
+msdos_dir_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ fat_file_fd_t *tmp_fat_fd = NULL;
+ struct dirent tmp_dirent;
+ unsigned32 start = 0;
+ ssize_t ret = 0;
+ unsigned32 cmpltd = 0;
+ unsigned32 j = 0, i = 0;
+ unsigned32 bts2rd = 0;
+ unsigned32 cur_cln = 0;
+
+ /*
+ * cast start and count - protect against using sizes that are not exact
+ * multiples of the -dirent- size. These could result in unexpected
+ * results
+ */
+ start = iop->offset / sizeof(struct dirent);
+ count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
+
+ /*
+ * optimization: we know that root directory for FAT12/16 volumes is
+ * sequential set of sectors and any cluster is sequential set of sectors
+ * too, so read such set of sectors is quick operation for low-level IO
+ * layer.
+ */
+ bts2rd = (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) ?
+ fat_fd->fat_file_size :
+ fs_info->fat.vol.bpc;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ while (count > 0)
+ {
+ /*
+ * fat-file is already opened by open call, so read it
+ * Always read directory fat-file from the beggining because of MSDOS
+ * directories feature :( - we should count elements currently
+ * present in the directory because there may be holes :)
+ */
+ ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, (j * bts2rd),
+ bts2rd, fs_info->cl_buf);
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EIO);
+ }
+
+ for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return cmpltd;
+ }
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY)
+ continue;
+
+ /*
+ * skip active entries until get the entry to start from
+ */
+ if (start)
+ {
+ start--;
+ continue;
+ }
+
+ /*
+ * Move the entry to the return buffer
+ *
+ * unfortunately there is no method to extract ino except to
+ * open fat-file descriptor :( ... so, open it
+ */
+
+ /* get number of cluster we are working with */
+ rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &cur_cln);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = fat_file_open(iop->pathinfo.mt_entry, cur_cln, i,
+ &tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ tmp_fat_fd->info_cln = cur_cln;
+ tmp_fat_fd->info_ofs = i;
+
+ /* fill in dirent structure */
+ /* XXX: from what and in what d_off should be computed ?! */
+ tmp_dirent.d_off = start + cmpltd;
+ tmp_dirent.d_reclen = sizeof(struct dirent);
+ tmp_dirent.d_ino = tmp_fat_fd->ino;
+ tmp_dirent.d_namlen = MSDOS_SHORT_NAME_LEN;
+ memcpy(tmp_dirent.d_name, MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_SHORT_NAME_LEN);
+
+ /* d_name is null-terminated */
+ tmp_dirent.d_name[MSDOS_SHORT_NAME_LEN] = 0;
+ memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
+
+ iop->offset = iop->offset + sizeof(struct dirent);
+ cmpltd += (sizeof(struct dirent));
+ count -= (sizeof(struct dirent));
+
+ /* inode number extracted, close fat-file */
+ rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (count <= 0)
+ break;
+ }
+ j++;
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return cmpltd;
+}
+
+/* msdos_dir_write --
+ * no write for directory
+ */
+
+/* msdos_dir_lseek --
+ *
+ * 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.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * offset - offset
+ * whence - predefine directive
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+int
+msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence)
+{
+ switch (whence)
+ {
+ case SEEK_SET:
+ case SEEK_CUR:
+ break;
+ /*
+ * Movement past the end of the directory via lseek is not a
+ * permitted operation
+ */
+ case SEEK_END:
+ default:
+ set_errno_and_return_minus_one( EINVAL );
+ break;
+ }
+ return RC_OK;
+}
+
+/* msdos_dir_stat --
+ *
+ * This routine will obtain the following information concerning the current
+ * directory:
+ * st_dev device id
+ * st_ino node serial number :)
+ * st_mode mode extracted from the node
+ * st_size total size in bytes
+ * st_blksize blocksize for filesystem I/O
+ * st_blocks number of blocks allocated
+ * stat_mtime time of last modification
+ *
+ * PARAMETERS:
+ * loc - this directory
+ * buf - stat buffer provided by user
+ *
+ * RETURNS:
+ * RC_OK and filled stat buffer on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+int
+msdos_dir_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+ )
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ buf->st_dev = fs_info->fat.vol.dev;
+ buf->st_ino = fat_fd->ino;
+ buf->st_mode = S_IFDIR;
+ buf->st_rdev = 0ll;
+ buf->st_size = fat_fd->fat_file_size;
+ buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
+ buf->st_blksize = fs_info->fat.vol.bps;
+ buf->st_mtime = fat_fd->mtime;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_truncate --
+ * No truncate for directory.
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ */
+
+/* msdos_dir_sync --
+ * The following routine does a syncronization on a MSDOS directory node.
+ * DIR_WrtTime, DIR_WrtDate and DIR_fileSize fields of 32 Bytes Directory
+ * Entry Structure(see M$ White Paper) should not be updated for
+ * directories, so only call to corresponding fat-file routine.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ */
+int
+msdos_dir_sync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_dir_rmnod --
+ * Remove directory node.
+ *
+ * Check that this directory node is not opened as fat-file, is empty and
+ * not filesystem root node. If all this conditions met then delete.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ */
+int
+msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = pathloc->node_access;
+ rtems_boolean is_empty = FALSE;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /*
+ * We deny attemp to delete open directory (if directory is current
+ * directory we assume it is open one)
+ */
+ if (fat_fd->links_num > 1)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EBUSY);
+ }
+
+ /*
+ * You cannot remove a node that still has children
+ */
+ rc = msdos_dir_is_empty(pathloc->mt_entry, fat_fd, &is_empty);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (!is_empty)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(ENOTEMPTY);
+ }
+
+ /*
+ * You cannot remove the file system root node.
+ */
+ if (pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EBUSY);
+ }
+
+ /*
+ * You cannot remove a mountpoint.
+ * not used - mount() not implemenetd yet.
+ */
+
+ /* mark file removed */
+ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
+ fat_fd->info_ofs,
+ MSDOS_THIS_DIR_ENTRY_EMPTY);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ fat_file_mark_removed(pathloc->mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_eval.c b/c/src/libfs/src/dosfs/msdos_eval.c
new file mode 100644
index 0000000000..3eba0e63e8
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_eval.c
@@ -0,0 +1,435 @@
+/*
+ * MSDOS evaluation routines
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_set_handlers --
+ * Set handlers for the node with specified type(i.e. handlers for file
+ * or directory).
+ *
+ * PARAMETERS:
+ * loc - node description
+ *
+ * RETURNS:
+ * None
+ */
+static void
+msdos_set_handlers(rtems_filesystem_location_info_t *loc)
+{
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ loc->handlers = fs_info->directory_handlers;
+ else
+ loc->handlers = fs_info->file_handlers;
+}
+
+/* msdos_eval_path --
+ *
+ * The following routine evaluate path for a node that wishes to be
+ * accessed. Structure 'pathloc' is returned with a pointer to the
+ * node to be accessed.
+ *
+ * PARAMETERS:
+ * pathname - path for evaluation
+ * flags - flags
+ * pathloc - node description (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK and filled pathloc on success, or -1 if error occured
+ * (errno set appropriately)
+ *
+ */
+int
+msdos_eval_path(
+ const char *pathname,
+ int flags,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ int i = 0;
+ int len = 0;
+ msdos_token_types_t type = MSDOS_CURRENT_DIR;
+ char token[MSDOS_NAME_MAX + 1];
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN))
+ {
+ type = msdos_get_token(&pathname[i], token, &len);
+ i += len;
+
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalpath_h)(&(pathname[i-len]),
+ flags, pathloc);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ /*
+ * Always return the root node.
+ *
+ * If we are at a node that is a mount point. Set loc to the
+ * new fs root node and let let the mounted filesystem set the handlers.
+ *
+ * NOTE: The behavior of stat() on a mount point appears to be
+ * questionable.
+ * NOTE: MSDOS filesystem currently doesn't support mount functionality ->
+ * action not implemented
+ */
+ fat_fd = pathloc->node_access;
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_eval4make --
+ * The following routine evaluate path for a new node to be created.
+ * 'pathloc' is returned with a pointer to the parent of the new node.
+ * 'name' is returned with a pointer to the first character in the
+ * new node name. The parent node is verified to be a directory.
+ *
+ * PARAMETERS:
+ * path - path for evaluation
+ * pathloc - IN/OUT (start point for evaluation/parent directory for
+ * creation)
+ * name - new node name
+ *
+ * RETURNS:
+ * RC_OK, filled pathloc for parent directory and name of new node on
+ * success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_eval4make(
+ const char *path,
+ rtems_filesystem_location_info_t *pathloc,
+ const char **name
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ msdos_token_types_t type;
+ int i = 0;
+ int len;
+ char token[ MSDOS_NAME_MAX + 1 ];
+ rtems_boolean done = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while (!done)
+ {
+ type = msdos_get_token(&path[i], token, &len);
+ i += len;
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalformake_h)(&path[i-len],
+ pathloc, name);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc)
+ {
+ if (rc != MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ else
+ done = TRUE;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ errno = EEXIST;
+ rc = -1;
+ goto error;
+ break;
+
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ *name = &path[i - len];
+
+ /*
+ * We have evaluated the path as far as we can.
+ * Verify there is not any invalid stuff at the end of the name.
+ */
+ for( ; path[i] != '\0'; i++)
+ {
+ if (!msdos_is_separator(path[i]))
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ }
+
+ fat_fd = pathloc->node_access;
+
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_file.c b/c/src/libfs/src/dosfs/msdos_file.c
new file mode 100644
index 0000000000..da36827338
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_file.c
@@ -0,0 +1,485 @@
+/*
+ * MSDOS file handlers implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_file_open --
+ * Open fat-file which correspondes to the file
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * pathname - name
+ * flag - flags
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK, if file opened successfully, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+msdos_file_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
+ unsigned32 mode)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (iop->flags & LIBIO_FLAGS_APPEND)
+ iop->offset = fat_fd->fat_file_size;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_close --
+ * Close fat-file which correspondes to the file. If fat-file descriptor
+ * which correspondes to the file is not marked "removed", synchronize
+ * size, first cluster number, write time and date fields of the file.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK, if file closed successfully, or -1 if error occured (errno set
+ * appropriately)
+ */
+int
+msdos_file_close(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /*
+ * if fat-file descriptor is not marked as "removed", synchronize
+ * size, first cluster number, write time and date fields of the file
+ */
+ if (!FAT_FILE_IS_REMOVED(fat_fd))
+ {
+ rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ }
+
+ rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_file_read --
+ * This routine read from file pointed to by file control block into
+ * the specified data buffer provided by user
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - buffer provided by user
+ * count - the number of bytes to read
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno set
+ * appropriately)
+ */
+ssize_t
+msdos_file_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
+{
+ ssize_t ret = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
+ buffer);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return ret;
+}
+
+/* msdos_file_write --
+ * This routine writes the specified data buffer into the file pointed to
+ * by file control block.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - data to write
+ * count - count of bytes to write
+ *
+ * RETURNS:
+ * the number of bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+msdos_file_write(rtems_libio_t *iop,const void *buffer, unsigned32 count)
+{
+ ssize_t ret = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ ret = fat_file_write(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
+ buffer);
+ if (ret < 0)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return -1;
+ }
+
+ /*
+ * update file size in both fat-file descriptor and file control block if
+ * file was extended
+ */
+ if (iop->offset + ret > fat_fd->fat_file_size)
+ fat_fd->fat_file_size = iop->offset + ret;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return ret;
+}
+
+/* msdos_file_lseek --
+ * Process lseek call to the file: extend file if lseek is up to the end
+ * of the file.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * offset - new offset
+ * whence - predefine directive
+ *
+ * RETURNS:
+ * new offset on success, or -1 if error occured (errno set
+ * appropriately).
+ */
+int
+msdos_file_lseek(rtems_libio_t *iop, off_t offset, int whence)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ unsigned32 real_size = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_extend(iop->pathinfo.mt_entry, fat_fd, iop->offset,
+ &real_size);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (real_size > fat_fd->fat_file_size)
+ fat_fd->fat_file_size = iop->offset = real_size;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return iop->offset;
+}
+
+/* msdos_file_stat --
+ *
+ * PARAMETERS:
+ * loc - node description
+ * buf - stat buffer provided by user
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+ )
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ buf->st_dev = fs_info->fat.vol.dev;
+ buf->st_ino = fat_fd->ino;
+ buf->st_mode = S_IFREG;
+ buf->st_rdev = 0ll;
+ buf->st_size = fat_fd->fat_file_size;
+ buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
+ buf->st_blksize = fs_info->fat.vol.bps;
+ buf->st_mtime = fat_fd->mtime;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_ftruncate --
+ * Truncate the file (if new length is greater then current do nothing).
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * length - new length
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ */
+int
+msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ if (length >= fat_fd->fat_file_size)
+ return RC_OK;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ /*
+ * fat_file_truncate do nothing if new length >= fat-file size, so update
+ * file size only if length < fat-file size
+ */
+ if (length < fat_fd->fat_file_size)
+ iop->size = fat_fd->fat_file_size = length;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_sync --
+ * Synchronize file - synchronize file data and if file is not removed
+ * synchronize file metadata.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_sync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* synchronize file data */
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ /*
+ * if fat-file descriptor is not marked "removed" - synchronize file
+ * metadata
+ */
+ if (!FAT_FILE_IS_REMOVED(fat_fd))
+ {
+ rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_datasync --
+ * Synchronize file - synchronize only file data (metadata is letf intact).
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_datasync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* synchronize file data */
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+
+/* msdos_file_ioctl --
+ *
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * ...
+ *
+ * RETURNS:
+ *
+ */
+int
+msdos_file_ioctl(rtems_libio_t *iop,unsigned32 command, void *buffer)
+{
+ int rc = RC_OK;
+
+ return rc;
+}
+
+/* msdos_file_rmnod --
+ * Remove node associated with a file - set up first name character to
+ * predefined value(and write it to the disk), and mark fat-file which
+ * correspondes to the file as "removed"
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = pathloc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* mark file removed */
+ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
+ fat_fd->info_ofs,
+ MSDOS_THIS_DIR_ENTRY_EMPTY);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ fat_file_mark_removed(pathloc->mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_free.c b/c/src/libfs/src/dosfs/msdos_free.c
new file mode 100644
index 0000000000..c0d5938dbb
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_free.c
@@ -0,0 +1,56 @@
+/*
+ * Free node handler implementation for the filesystem
+ * operations table.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <errno.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_free_node_info --
+ * Call fat-file close routine.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 code if error occured
+ *
+ */
+int
+msdos_free_node_info(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_close(pathloc->mt_entry, pathloc->node_access);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_fsunmount.c b/c/src/libfs/src/dosfs/msdos_fsunmount.c
new file mode 100644
index 0000000000..9072a2fad5
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_fsunmount.c
@@ -0,0 +1,71 @@
+/*
+ * MSDOS shut down handler implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_shut_down --
+ * Shut down MSDOS filesystem - free all allocated resources (don't
+ * return if deallocation of some resource failed - free as much as
+ * possible).
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = temp_mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = temp_mt_entry->mt_fs_root.node_access;
+
+ /* close fat-file which correspondes to root directory */
+ if (fat_file_close(temp_mt_entry, fat_fd) != RC_OK)
+ {
+ /* no return - try to free as much as possible */
+ rc = -1;
+ }
+
+ if (fat_shutdown_drive(temp_mt_entry) != RC_OK)
+ {
+ /* no return - try to free as much as possible */
+ rc = -1;
+ }
+
+ rtems_semaphore_delete(fs_info->vol_sema);
+ free(fs_info->cl_buf);
+ free(temp_mt_entry->fs_info);
+
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_handlers_dir.c b/c/src/libfs/src/dosfs/msdos_handlers_dir.c
new file mode 100644
index 0000000000..e14d892add
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_handlers_dir.c
@@ -0,0 +1,36 @@
+/*
+ * Directory Handlers Table for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio.h>
+#include "msdos.h"
+
+rtems_filesystem_file_handlers_r msdos_dir_handlers = {
+ msdos_dir_open,
+ msdos_dir_close,
+ msdos_dir_read,
+ NULL, /* msdos_dir_write */
+ NULL, /* msdos_dir_ioctl */
+ msdos_dir_lseek,
+ msdos_dir_stat,
+ NULL,
+ NULL, /* msdos_dir_ftruncate */
+ NULL,
+ msdos_dir_sync,
+ msdos_dir_sync,
+ NULL, /* msdos_dir_fcntl */
+ msdos_dir_rmnod
+};
diff --git a/c/src/libfs/src/dosfs/msdos_handlers_file.c b/c/src/libfs/src/dosfs/msdos_handlers_file.c
new file mode 100644
index 0000000000..ae627066de
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_handlers_file.c
@@ -0,0 +1,36 @@
+/*
+ * File Operations Table for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio.h>
+#include "msdos.h"
+
+rtems_filesystem_file_handlers_r msdos_file_handlers = {
+ msdos_file_open,
+ msdos_file_close,
+ msdos_file_read,
+ msdos_file_write,
+ msdos_file_ioctl,
+ msdos_file_lseek,
+ msdos_file_stat,
+ NULL,
+ msdos_file_ftruncate,
+ NULL,
+ msdos_file_sync,
+ msdos_file_datasync,
+ NULL, /* msdos_file_fcntl */
+ msdos_file_rmnod
+};
diff --git a/c/src/libfs/src/dosfs/msdos_init.c b/c/src/libfs/src/dosfs/msdos_init.c
new file mode 100644
index 0000000000..2d5bf6c9e0
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_init.c
@@ -0,0 +1,60 @@
+/*
+ * Init routine for MSDOS
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio_.h>
+#include "msdos.h"
+
+rtems_filesystem_operations_table msdos_ops = {
+ msdos_eval_path,
+ msdos_eval4make,
+ NULL, /* msdos_link */
+ msdos_file_rmnod,
+ msdos_node_type,
+ msdos_mknod,
+ NULL, /* msdos_chown */
+ msdos_free_node_info,
+ NULL,
+ msdos_initialize,
+ NULL,
+ msdos_shut_down, /* msdos_shut_down */
+ NULL, /* msdos_utime */
+ NULL,
+ NULL,
+ NULL
+};
+
+/* msdos_initialize --
+ * MSDOS filesystem initialization
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
+{
+ int rc = RC_OK;
+
+ rc = msdos_initialize_support(temp_mt_entry,
+ &msdos_ops,
+ &msdos_file_handlers,
+ &msdos_dir_handlers);
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_initsupp.c b/c/src/libfs/src/dosfs/msdos_initsupp.c
new file mode 100644
index 0000000000..eee8a6f9b2
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_initsupp.c
@@ -0,0 +1,149 @@
+/*
+ * MSDOS Initialization support routine implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_initialize_support --
+ * MSDOS filesystem initialization
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ * op_table - filesystem operations table
+ * file_handlers - file operations table
+ * directory_handlers - directory operations table
+ *
+ * RETURNS:
+ * RC_OK and filled temp_mt_entry on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_initialize_support(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry,
+ rtems_filesystem_operations_table *op_table,
+ rtems_filesystem_file_handlers_r *file_handlers,
+ rtems_filesystem_file_handlers_r *directory_handlers
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = NULL;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned32 cl_buf_size;
+
+ fs_info = (msdos_fs_info_t *)calloc(1, sizeof(msdos_fs_info_t));
+ if (!fs_info)
+ set_errno_and_return_minus_one(ENOMEM);
+
+ temp_mt_entry->fs_info = fs_info;
+
+ rc = fat_init_volume_info(temp_mt_entry);
+ if (rc != RC_OK)
+ {
+ free(fs_info);
+ return rc;
+ }
+
+ fs_info->file_handlers = file_handlers;
+ fs_info->directory_handlers = directory_handlers;
+
+ /*
+ * open fat-file which correspondes to root directory
+ * (so inode number 0x00000010 is always used for root directory)
+ */
+ rc = fat_file_open(temp_mt_entry, FAT_ROOTDIR_CLUSTER_NUM, 0, &fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ return rc;
+ }
+
+ /* again: unfortunately "fat-file" is just almost fat file :( */
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+ fat_fd->info_cln = FAT_ROOTDIR_CLUSTER_NUM;
+ fat_fd->info_ofs = 0;
+ fat_fd->cln = fs_info->fat.vol.rdir_cl;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ /* if we have FAT12/16 */
+ if ( fat_fd->cln == 0 )
+ {
+ fat_fd->fat_file_size = fs_info->fat.vol.rdir_size;
+ cl_buf_size = (fs_info->fat.vol.bpc > fs_info->fat.vol.rdir_size) ?
+ fs_info->fat.vol.bpc :
+ fs_info->fat.vol.rdir_size;
+ }
+ else
+ {
+ rc = fat_file_size(temp_mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ return rc;
+ }
+ cl_buf_size = fs_info->fat.vol.bpc;
+ }
+
+ fs_info->cl_buf = (char *)calloc(cl_buf_size, sizeof(char));
+ if (fs_info->cl_buf == NULL)
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_semaphore_create(3,
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO,
+ RTEMS_INHERIT_PRIORITY,
+ &fs_info->vol_sema);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info->cl_buf);
+ free(fs_info);
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ temp_mt_entry->mt_fs_root.node_access = fat_fd;
+ temp_mt_entry->mt_fs_root.handlers = directory_handlers;
+ temp_mt_entry->mt_fs_root.ops = op_table;
+
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_misc.c b/c/src/libfs/src/dosfs/msdos_misc.c
new file mode 100644
index 0000000000..fe2779f7a8
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_misc.c
@@ -0,0 +1,1087 @@
+/*
+ * Miscellaneous routines implementation for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* This copied from Linux */
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+#undef CONFIG_ATARI
+
+/* MS-DOS "device special files" */
+static const char *reserved_names[] = {
+#ifndef CONFIG_ATARI /* GEMDOS is less stupid */
+ "CON ","PRN ","NUL ","AUX ",
+ "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
+ "COM1 ","COM2 ","COM3 ","COM4 ",
+#endif
+ NULL };
+
+static char bad_chars[] = "*?<>|\"";
+#ifdef CONFIG_ATARI
+/* GEMDOS is less restrictive */
+static char bad_if_strict[] = " ";
+#else
+static char bad_if_strict[] = "+=,; ";
+#endif
+
+/* The following three functions copied from Linux */
+/*
+ * Formats an MS-DOS file name. Rejects invalid names
+ *
+ * conv is relaxed/normal/strict, name is proposed name,
+ * len is the length of the proposed name, res is the result name,
+ * dotsOK is if hidden files get dots.
+ */
+int
+msdos_format_name(char conv, const char *name, int len, char *res,
+ char dotsOK)
+{
+ char *walk;
+ const char **reserved;
+ unsigned char c;
+ int space;
+ if (name[0] == '.') { /* dotfile because . and .. already done */
+ if (!dotsOK) return -EINVAL;
+ /* Get rid of dot - test for it elsewhere */
+ name++; len--;
+ }
+#ifndef CONFIG_ATARI
+ space = 1; /* disallow names that _really_ start with a dot */
+#else
+ space = 0; /* GEMDOS does not care */
+#endif
+ c = 0;
+ for (walk = res; len && walk-res < 8; walk++) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
+/* 0xE5 is legal as a first character, but we must substitute 0x05 */
+/* because 0xE5 marks deleted files. Yes, DOS really does this. */
+/* It seems that Microsoft hacked DOS to support non-US characters */
+/* after the 0xE5 character was already in use to mark deleted files. */
+ if((res==walk) && (c==0xE5)) c=0x05;
+ if (c == '.') break;
+ space = (c == ' ');
+ *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len && c != '.') {
+ c = *name++;
+ len--;
+ if (c != '.') return -EINVAL;
+ }
+ while (c != '.' && len--) c = *name++;
+ if (c == '.') {
+ while (walk-res < 8) *walk++ = ' ';
+ while (len > 0 && walk-res < MSDOS_NAME_MAX) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c))
+ return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\')
+ return -EINVAL;
+ if (c == '.') {
+ if (conv == 's')
+ return -EINVAL;
+ break;
+ }
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ space = c == ' ';
+ *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len) return -EINVAL;
+ }
+ while (walk-res < MSDOS_NAME_MAX) *walk++ = ' ';
+ for (reserved = reserved_names; *reserved; reserved++)
+ if (!strncmp(res,*reserved,8)) return -EINVAL;
+ return 0;
+}
+
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70) */
+unsigned int
+msdos_date_dos2unix(unsigned short time_val,unsigned short date)
+{
+ int month,year,secs;
+
+ month = ((date >> 5) & 15)-1;
+ year = date >> 9;
+ secs = (time_val & 31)*2+60*((time_val >> 5) & 63)+
+ (time_val >> 11)*3600+86400*
+ ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
+ month < 2 ? 1 : 0)+3653);
+ /* days since 1.1.70 plus 80's leap day */
+
+ return secs;
+}
+
+
+/* Convert linear UNIX date to a MS-DOS time/date pair */
+void msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date)
+{
+ int day,year,nl_day,month;
+
+ *time_val = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
+ (((unix_date/3600) % 24) << 11);
+ day = unix_date/86400-3652;
+ year = day/365;
+ if ((year+3)/4+365*year > day) year--;
+ day -= (year+3)/4+365*year;
+ if (day == 59 && !(year & 3)) {
+ nl_day = day;
+ month = 2;
+ }
+ else {
+ nl_day = (year & 3) || day <= 59 ? day : day-1;
+ for (month = 0; month < 12; month++)
+ if (day_n[month] > nl_day) break;
+ }
+ *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+}
+
+
+/* msdos_get_token --
+ * Routine to get a token (name or separator) from the path.
+ *
+ * PARAMETERS:
+ * path - path to get token from
+ * ret_token - returned token
+ * token_len - length of returned token
+ *
+ * RETURNS:
+ * token type, token and token length
+ *
+ */
+msdos_token_types_t
+msdos_get_token(const char *path, char *ret_token, int *token_len)
+{
+ int rc = RC_OK;
+ register int i = 0;
+ msdos_token_types_t type = MSDOS_NAME;
+ char token[MSDOS_NAME_MAX_WITH_DOT+1];
+ register char c;
+
+ /*
+ * Copy a name into token. (Remember NULL is a token.)
+ */
+ c = path[i];
+ while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) )
+ {
+ token[i] = c;
+ if ( i == MSDOS_NAME_MAX_WITH_DOT )
+ return MSDOS_INVALID_TOKEN;
+ if ( !msdos_is_valid_name_char(c) )
+ return MSDOS_INVALID_TOKEN;
+ c = path [++i];
+ }
+
+ /*
+ * Copy a seperator into token.
+ */
+ if ( i == 0 )
+ {
+ token[i] = c;
+ if ( token[i] != '\0' )
+ {
+ i++;
+ type = MSDOS_CURRENT_DIR;
+ }
+ else
+ type = MSDOS_NO_MORE_PATH;
+ }
+ else if (token[ i-1 ] != '\0')
+ token[i] = '\0';
+
+ /*
+ * Set token_len to the number of characters copied.
+ */
+ *token_len = i;
+
+ /*
+ * If we copied something that was not a seperator see if
+ * it was a special name.
+ */
+ if ( type == MSDOS_NAME )
+ {
+ if ( strcmp( token, "..") == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOTDOT_NAME);
+ type = MSDOS_UP_DIR;
+ return type;
+ }
+
+ if ( strcmp( token, "." ) == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOT_NAME);
+ type = MSDOS_CURRENT_DIR;
+ return type;
+ }
+
+ rc = msdos_format_name('r', token, *token_len, ret_token, 0);
+ if ( rc != RC_OK )
+ return MSDOS_INVALID_TOKEN;
+ }
+ ret_token[MSDOS_NAME_MAX] = '\0';
+ return type;
+}
+
+
+/* msdos_find_name --
+ * Find the node which correspondes to the name, open fat-file which
+ * correspondes to the found node and close fat-file which correspondes
+ * to the node we searched in.
+ *
+ * PARAMETERS:
+ * parent_loc - parent node description
+ * name - name to find
+ *
+ * RETURNS:
+ * RC_OK and updated 'parent_loc' on success, or -1 if error
+ * occured (errno set apropriately)
+ *
+ */
+int
+msdos_find_name(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ fat_auxiliary_t aux;
+ unsigned short time_val = 0;
+ unsigned short date = 0;
+ unsigned char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+
+ memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * find the node which correspondes to the name in the directory pointed by
+ * 'parent_loc'
+ */
+ rc = msdos_get_name_node(parent_loc, name, &aux, node_entry);
+ if (rc != RC_OK)
+ return rc;
+
+ /* open fat-file corresponded to the found node */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * I don't like this if, but: we should do it , or should write new file
+ * size and first cluster num to the disk after each write operation
+ * (even if one byte is written - that is TOO non-optimize) because
+ * otherwise real values of these fields stored in fat-file descriptor
+ * may be accidentely rewritten with wrong values stored on the disk
+ */
+ if (fat_fd->links_num == 1)
+ {
+ fat_fd->info_cln = aux.cln;
+ fat_fd->info_ofs = aux.ofs;
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
+ fat_fd->first_char = *MSDOS_DIR_NAME(node_entry);
+
+ time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
+ date = *MSDOS_DIR_WRITE_DATE(node_entry);
+
+ fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date));
+
+ if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
+ {
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ rc = fat_file_size(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+ }
+ else
+ {
+ fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
+ fat_fd->fat_file_type = FAT_FILE;
+ fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
+ }
+
+ /* these data is not actual for zero-length fat-file */
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ if ((fat_fd->fat_file_size != 0) &&
+ (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
+ {
+ fat_fd->map.last_cln = fat_fd->cln;
+ }
+ else
+ {
+ fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+ }
+ }
+
+ /* close fat-file corresponded to the node we searched in */
+ rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* update node_info_ptr field */
+ parent_loc->node_access = fat_fd;
+
+ return rc;
+}
+
+/* msdos_get_name_node --
+ * This routine is used in two ways: for a new mode creation (a) or for
+ * search the node which correspondes to the name parameter (b).
+ * In case (a) 'name' should be set up to NULL and 'name_dir_entry' should
+ * point to initialized 32 bytes structure described a new node.
+ * In case (b) 'name' should contain a valid string.
+ *
+ * (a): reading fat-file which correspondes to directory we are going to
+ * create node in. If free slot is found write contents of
+ * 'name_dir_entry' into it. If reach end of fat-file and no free
+ * slot found, write 32 bytes to the end of fat-file.
+ *
+ * (b): reading fat-file which correspondes to directory and trying to
+ * find slot with the name field == 'name' parameter
+ *
+ *
+ * PARAMETERS:
+ * parent_loc - node description to create node in or to find name in
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if
+ * error occured (errno set apropriately)
+ *
+ */
+int
+msdos_get_name_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = parent_loc->node_access;
+ unsigned32 dotdot_cln = 0;
+
+ /* find name in fat-file which correspondes to the directory */
+ rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, name, paux,
+ name_dir_entry);
+ if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
+ return rc;
+
+ /* if we search for valid name and name not found -> return */
+ if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name != NULL))
+ return rc;
+
+ /*
+ * if we try to create new entry and the directory is not big enough
+ * currently - try to enlarge directory
+ */
+ if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name == NULL))
+ {
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd,
+ fat_fd->fat_file_size,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ name_dir_entry);
+ if (ret == -1)
+ return -1;
+
+ /* on success directory is enlarged by a new cluster */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* get cluster num where a new node located */
+ rc = fat_file_ioctl(parent_loc->mt_entry, fat_fd, F_CLU_NUM,
+ fat_fd->fat_file_size - 1, &paux->cln);
+
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * if new cluster allocated succesfully then new node is at very
+ * beginning of the cluster (offset is computed in bytes)
+ */
+ paux->ofs = 0;
+ return RC_OK;
+ }
+
+ /*
+ * if we have deal with ".." - it is a special case :(((
+ *
+ * Really, we should return cluster num and offset not of ".." slot, but
+ * slot which correspondes to real directory name.
+ */
+ if ((rc == RC_OK) && (name != NULL))
+ {
+ if (strncmp(name, MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry));
+
+ /* are we right under root dir ? */
+ if (dotdot_cln == 0)
+ {
+ /*
+ * we can relax about first_char field - it never should be
+ * used for root dir
+ */
+ paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
+ paux->ofs = 0;
+ }
+ else
+ {
+ rc = msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ parent_loc->mt_entry,
+ dotdot_cln,
+ paux,
+ name_dir_entry
+ );
+ if (rc != RC_OK)
+ return rc;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+ * msdos_get_dotdot_dir_info_cluster_num_and_offset
+ *
+ * Unfortunately, in general, we cann't work here in fat-file ideologic
+ * (open fat_file "..", get ".." and ".", open "..", find an entry ...)
+ * because if we open
+ * fat-file ".." it may happend that we have two different fat-file
+ * descriptors ( for real name of directory and ".." name ) for a single
+ * file ( cluster num of both pointers to the same cluster )
+ * But...we do it because we protected by semaphore
+ *
+ */
+
+/* msdos_get_dotdot_dir_info_cluster_num_and_offset --
+ * Get cluster num and offset not of ".." slot, but slot which correspondes
+ * to real directory name.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - data cluster num extracted drom ".." slot
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned char dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char cur_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned32 cl4find = 0;
+
+ memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(cur_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * open fat-file corresponded to ".."
+ */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ fat_fd->info_cln = paux->cln;
+ fat_fd->info_ofs = paux->ofs;
+ fat_fd->cln = cln;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find "." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux,
+ dot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find ".." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux,
+ dotdot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
+
+ /* close fat-file corresponded to ".." directory */
+ rc = fat_file_close(mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ return rc;
+
+ if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ {
+ /*
+ * we handle root dir for all FAT types in the same way with the
+ * ordinary directories ( through fat_file_* calls )
+ */
+ paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
+ paux->ofs = 0;
+ }
+
+ /* open fat-file corresponded to second ".." */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ fat_fd->info_cln = paux->cln;
+ fat_fd->info_ofs = paux->ofs;
+
+ if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ fat_fd->cln = fs_info->fat.vol.rdir_cl;
+ else
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
+
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* in this directory find slot with specified cluster num */
+ rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
+ paux, dir_entry);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+ rc = fat_file_close(mt_entry, fat_fd);
+ return rc;
+}
+
+
+/* msdos_set_dir_wrt_time_and_date --
+ * Write last write date and time for a file to the disk (to corresponded
+ * 32bytes node)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned short time_val;
+ unsigned short date;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ msdos_date_unix2dos(fat_fd->mtime, &time_val, &date);
+
+ /*
+ * calculate input for _fat_block_write: convert (cluster num, offset) to
+ * (sector num, new offset)
+ */
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ /* byte points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ time_val = CT_LE_W(time_val);
+ ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET,
+ 2, (char *)(&time_val));
+ date = CT_LE_W(date);
+ ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET,
+ 2, (char *)(&date));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_set_first_cluster_num --
+ * Write number of first cluster of the file to the disk (to corresponded
+ * 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_set_first_cluster_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 new_cln = fat_fd->cln;
+ unsigned16 le_cl_low = 0;
+ unsigned16 le_cl_hi = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ /*
+ * calculate input for _fat_block_write: convert (cluster num, offset) to
+ * (sector num, new offset)
+ */
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ /* byte from points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ le_cl_low = CT_LE_W((unsigned16)(new_cln & 0x0000FFFF));
+ ret1 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
+ (char *)(&le_cl_low));
+ le_cl_hi = CT_LE_W((unsigned16)((new_cln & 0xFFFF0000) >> 16));
+ ret2 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
+ (char *)(&le_cl_hi));
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+
+/* msdos_set_file size --
+ * Write file size of the file to the disk (to corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_new_length = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1));
+
+ le_new_length = CT_LE_L((fat_fd->fat_file_size));
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
+ (char *)(&le_new_length));
+ if ( ret < 0 )
+ return -1;
+
+ return RC_OK;
+}
+
+/*
+ * We should not check whether this routine is called for root dir - it
+ * never can happend
+ */
+
+/* msdos_set_first_char4file_name --
+ * Write first character of the name of the file to the disk (to
+ * corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cl - number of cluster
+ * ofs - offset inside cluster
+ * fchar - character to set up
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately)
+ *
+ */
+int
+msdos_set_first_char4file_name(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char fchar
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cl);
+ sec += (ofs >> fs_info->fat.vol.sec_log2);
+ byte = (ofs & (fs_info->fat.vol.bps - 1));
+
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1,
+ &fchar);
+ if ( ret < 0)
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_dir_is_empty --
+ * Check whether directory which correspondes to the fat-file descriptor is
+ * empty.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * ret_val - placeholder for result
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_dir_is_empty(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0, i = 0;
+
+ /* dir is not empty */
+ *ret_val = FALSE;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
+ fs_info->fat.vol.bps,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ assert(ret == fs_info->fat.vol.bps);
+
+ for (i = 0;
+ i < fs_info->fat.vol.bps;
+ i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_DOTDOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0))
+ continue;
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ *ret_val = TRUE;
+ return RC_OK;
+ }
+ return RC_OK;
+ }
+ j++;
+ }
+ *ret_val = TRUE;
+ return RC_OK;
+}
+
+
+/* msdos_find_name_in_fat_file --
+ * This routine is used in two ways: for a new mode creation (a) or for
+ * search the node which correspondes to the 'name' parameter (b).
+ * In case (a) name should be set up to NULL and 'name_dir_entry' should
+ * point to initialized 32 bytes structure described a new node.
+ * In case (b) 'name' should contain a valid string.
+ *
+ * (a): reading fat-file corresponded to directory we are going to create
+ * node in. If found free slot write contents of name_dir_entry into
+ * it.
+ *
+ * (b): reading fat-file corresponded to directory and trying to find slot
+ * with the name field == name parameter
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ */
+int
+msdos_find_name_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 i = 0, j = 0;
+ unsigned32 bts2rd = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
+ bts2rd = fat_fd->fat_file_size;
+ else
+ bts2rd = fs_info->fat.vol.bpc;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ set_errno_and_return_minus_one(EIO);
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* is the entry empty ? */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
+ ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY))
+ {
+ /* whether we are looking for an empty entry */
+ if (name == NULL)
+ {
+ /* get current cluster number */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ /* offset is computed in bytes */
+ paux->ofs = i;
+
+ /* write new node entry */
+ ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ name_dir_entry);
+ if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ /*
+ * we don't update fat_file_size here - it should not
+ * increase
+ */
+ return RC_OK;
+ }
+
+ /*
+ * if name != NULL and there is no more entries in the
+ * directory - return name-not-found
+ */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY))
+ return MSDOS_NAME_NOT_FOUND_ERR;
+ }
+ else
+ {
+ /* entry not empty and name != NULL -> compare names */
+ if (name != NULL)
+ {
+ if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name,
+ MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ /*
+ * we get the entry we looked for - fill auxiliary
+ * structure and copy all 32 bytes of the entry
+ */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ /* offset is computed in bytes */
+ paux->ofs = i;
+ memcpy(name_dir_entry,(fs_info->cl_buf + i),
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
+
+/* msdos_find_node_by_cluster_num_in_fat_file --
+ * Find node with specified number of cluster in fat-file.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * cl4find - number of cluster to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured
+ *
+ */
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 bts2rd = 0;
+ unsigned32 i = 0, j = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
+ bts2rd = fat_fd->fat_file_size;
+ else
+ bts2rd = fs_info->fat.vol.bpc;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * bts2rd, bts2rd,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
+ set_errno_and_return_minus_one( EIO );
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* if this and all rest entries are empty - return not-found */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ return MSDOS_NAME_NOT_FOUND_ERR;
+
+ /* if this entry is empty - skip it */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY)
+ continue;
+
+ /* if get a non-empty entry - compare clusters num */
+ if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find)
+ {
+ /* on success fill aux structure and copy all 32 bytes */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd,
+ &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ paux->ofs = i;
+ memcpy(dir_entry, fs_info->cl_buf + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_mknod.c b/c/src/libfs/src/dosfs/msdos_mknod.c
new file mode 100644
index 0000000000..5e32dbf3bf
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_mknod.c
@@ -0,0 +1,90 @@
+/*
+ * Routine for node creation in MSDOS filesystem.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_mknod --
+ * The following function checks spelling and formats name for a new node,
+ * determines type of the node to be created and creates it.
+ *
+ * PARAMETERS:
+ * token - non-formatted name of a new node
+ * mode - node type
+ * dev - dev
+ * pathloc - parent directory description
+ *
+ * RETURNS:
+ * RC_OK on succes, or -1 if error occured and set errno
+ *
+ */
+int
+msdos_mknod(
+ const char *token,
+ mode_t mode,
+ dev_t dev,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ msdos_token_types_t type = 0;
+ char new_name[ MSDOS_NAME_MAX + 1 ];
+ int len;
+
+ /* check spelling and format new node name */
+ msdos_get_token(token, new_name, &len);
+
+ /*
+ * Figure out what type of msdos node this is.
+ */
+ if (S_ISDIR(mode))
+ {
+ type = MSDOS_DIRECTORY;
+ }
+ else if (S_ISREG(mode))
+ {
+ type = MSDOS_REGULAR_FILE;
+ }
+ else
+ set_errno_and_return_minus_one(EINVAL);
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* Create an MSDOS node */
+ rc = msdos_creat_node(pathloc, type, new_name, mode);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/c/src/libfs/src/dosfs/msdos_node_type.c b/c/src/libfs/src/dosfs/msdos_node_type.c
new file mode 100644
index 0000000000..517dabda3f
--- /dev/null
+++ b/c/src/libfs/src/dosfs/msdos_node_type.c
@@ -0,0 +1,58 @@
+/*
+ * The following returns the type of node that the loc refers to.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_node_type --
+ * Determine type of the node that the pathloc refers to.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * node type
+ *
+ */
+rtems_filesystem_node_types_t
+msdos_node_type(rtems_filesystem_location_info_t *pathloc)
+{
+ fat_file_fd_t *fat_fd;
+
+ /*
+ * we don't need to obtain the volume semaphore here because node_type_h
+ * call always follows evalpath_h call(hence link increment occured) and
+ * hence node_access memory can't be freed during processing node_type_h
+ * call
+ */
+ fat_fd = pathloc->node_access;
+
+ return fat_fd->fat_file_type;
+}
diff --git a/c/src/libfs/src/dosfs/stamp-h2.in b/c/src/libfs/src/dosfs/stamp-h2.in
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/c/src/libfs/src/dosfs/stamp-h2.in
diff --git a/c/src/libfs/wrapup/Makefile.am b/c/src/libfs/wrapup/Makefile.am
index 5dfd76e83d..13406dcb5f 100644
--- a/c/src/libfs/wrapup/Makefile.am
+++ b/c/src/libfs/wrapup/Makefile.am
@@ -13,7 +13,9 @@ include $(top_srcdir)/../../../automake/lib.am
IMFSLIB = ../src/imfs/$(ARCH)/libimfs.a
-TMP_LIBS = $(IMFSLIB)
+DOSFSLIB = ../src/dosfs/$(ARCH)/libdosfs.a
+
+TMP_LIBS = $(IMFSLIB) $(DOSFSLIB)
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@
diff --git a/cpukit/libfs/ChangeLog b/cpukit/libfs/ChangeLog
index b4dd8e9f61..4166f2e369 100644
--- a/cpukit/libfs/ChangeLog
+++ b/cpukit/libfs/ChangeLog
@@ -1,3 +1,20 @@
+2002-02-28 Victor V. Vengerov <vvv@oktet.ru>
+
+ * DOS filesystem including FAT12, FAT16, and FAT32 support submitted.
+ * src/dosfs, src/dosfs/Makefile.am, src/dosfs/stamp-h2.in,
+ src/dosfs/config.h.in, src/dosfs/dosfs.h, src/dosfs/fat.c,
+ src/dosfs/fat.h, src/dosfs/fat_fat_operations.c,
+ src/dosfs/fat_fat_operations.h, src/dosfs/fat_file.c,
+ src/dosfs/fat_file.h, src/dosfs/msdos.h, src/dosfs/msdos_create.c,
+ src/dosfs/msdos_dir.c, src/dosfs/msdos_eval.c, src/dosfs/msdos_file.c,
+ src/dosfs/msdos_free.c, src/dosfs/msdos_fsunmount.c,
+ src/dosfs/msdos_handlers_dir.c, src/dosfs/msdos_handlers_file.c,
+ src/dosfs/msdos_init.c, src/dosfs/msdos_initsupp.c,
+ src/dosfs/msdos_misc.c, src/dosfs/msdos_mknod.c,
+ src/dosfs/msdos_node_type.c, src/dosfs/.cvsignore: New files.
+ * configure.ac, src/Makefile.am, wrapup/Makefile.am: Modified to
+ reflect addition.
+
2002-01-07 Ralf Corsepius <corsepiu@faw.uni-ulm.de>
* src/imfs/imfs_load_tar.c: Add include <sys/types.h>.
diff --git a/cpukit/libfs/configure.ac b/cpukit/libfs/configure.ac
index 4e2adeb1b5..7f36fac28e 100644
--- a/cpukit/libfs/configure.ac
+++ b/cpukit/libfs/configure.ac
@@ -5,6 +5,7 @@
AC_PREREQ(2.52)
AC_INIT
AC_CONFIG_SRCDIR([src/imfs/imfs.h])
+AC_CONFIG_SRCDIR([src/dosfs/dosfs.h])
RTEMS_TOP(../../..)
AC_CONFIG_AUX_DIR(../../..)
@@ -27,11 +28,13 @@ RTEMS_CANONICALIZE_TOOLS
AM_CONDITIONAL(UNIX,test x"$RTEMS_CPU" = x"unix")
AM_CONFIG_HEADER(src/imfs/config.h)
+AM_CONFIG_HEADER(src/dosfs/config.h)
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
src/Makefile
src/imfs/Makefile
+src/dosfs/Makefile
wrapup/Makefile
])
AC_OUTPUT
diff --git a/cpukit/libfs/src/Makefile.am b/cpukit/libfs/src/Makefile.am
index 126a226126..fcd82899b4 100644
--- a/cpukit/libfs/src/Makefile.am
+++ b/cpukit/libfs/src/Makefile.am
@@ -4,7 +4,7 @@
AUTOMAKE_OPTIONS = foreign 1.4
-SUBDIRS = imfs
+SUBDIRS = imfs dosfs
include $(top_srcdir)/../../../automake/subdirs.am
include $(top_srcdir)/../../../automake/local.am
diff --git a/cpukit/libfs/src/dosfs/.cvsignore b/cpukit/libfs/src/dosfs/.cvsignore
new file mode 100644
index 0000000000..7bb609bf24
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+config.h
+config.h.in
+stamp-h
+stamp-h.in
diff --git a/cpukit/libfs/src/dosfs/Makefile.am b/cpukit/libfs/src/dosfs/Makefile.am
new file mode 100644
index 0000000000..44c9f4cd2f
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/Makefile.am
@@ -0,0 +1,80 @@
+##
+## $Id$
+##
+
+AUTOMAKE_OPTIONS = foreign 1.4
+
+INCLUDES = -I.
+
+LIBNAME = libdosfs
+LIB = ${ARCH}/${LIBNAME}.a
+
+FATFS_C_FILES = fat.c fat_fat_operations.c fat_file.c
+
+DOSFS_C_FILES = msdos_create.c msdos_dir.c msdos_eval.c msdos_file.c \
+ msdos_free.c msdos_fsunmount.c msdos_handlers_dir.c \
+ msdos_handlers_file.c msdos_init.c msdos_initsupp.c \
+ msdos_misc.c msdos_mknod.c msdos_node_type.c
+
+
+UNIX_C_FILES = msdos_unixstub.c
+
+EMBEDDED_C_FILES = $(FATFS_C_FILES) $(DOSFS_C_FILES)
+
+COMMON_C_FILES =
+
+if UNIX
+C_FILES = $(COMMON_C_FILES) $(UNIX_C_FILES)
+else
+C_FILES = $(COMMON_C_FILES) $(EMBEDDED_C_FILES)
+endif
+C_O_FILES = $(C_FILES:%.c=${ARCH}/%.o)
+
+include_HEADERS = fat.h fat_fat_operations.h \
+ fat_file.h msdos.h dosfs.h
+SYS_H_FILES =
+RTEMS_H_FILES =
+noinst_HEADERS =
+
+include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
+include $(top_srcdir)/../../../automake/compile.am
+include $(top_srcdir)/../../../automake/lib.am
+
+PREINSTALL_FILES = $(PROJECT_INCLUDE) $(PROJECT_INCLUDE)/rtems \
+ $(PROJECT_INCLUDE)/sys $(include_HEADERS:%=$(PROJECT_INCLUDE)/%) \
+ $(RTEMS_H_FILES:%=$(PROJECT_INCLUDE)/rtems/%) \
+ $(SYS_H_FILES:%=$(PROJECT_INCLUDE)/sys/%)
+
+$(PROJECT_INCLUDE):
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/rtems:
+ @$(mkinstalldirs) $@
+$(PROJECT_INCLUDE)/sys:
+ @$(mkinstalldirs) $@
+
+$(PROJECT_INCLUDE)/%.h: %.h
+ $(INSTALL_DATA) $< $@
+$(PROJECT_INCLUDE)/rtems/%.h: %.h
+ $(INSTALL_DATA) $< $@
+$(PROJECT_INCLUDE)/sys/%.h: %.h
+ $(INSTALL_DATA) $< $@
+
+OBJS = $(C_O_FILES)
+
+#
+# Add local stuff here using +=
+#
+
+AM_CFLAGS += $(LIBC_DEFINES)
+
+all-local: ${ARCH} $(LIB)
+
+$(LIB): ${OBJS}
+ $(make-library)
+
+DOC_FILES =
+
+EXTRA_DIST = $(DOC_FILES) $(COMMON_C_FILES) $(EMBEDDED_C_FILES) \
+ $(UNIX_C_FILES) $(RTEMS_H_FILES) $(SYS_H_FILES)
+
+include $(top_srcdir)/../../../automake/local.am
diff --git a/cpukit/libfs/src/dosfs/dosfs.h b/cpukit/libfs/src/dosfs/dosfs.h
new file mode 100644
index 0000000000..4cea929d4c
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/dosfs.h
@@ -0,0 +1,31 @@
+/*
+ * dosfs.h
+ *
+ * Application interface to MSDOS filesystem.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_DOSFS_H__
+#define __DOSFS_DOSFS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio.h>
+
+extern rtems_filesystem_operations_table msdos_ops;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_DOSFS_H__ */
diff --git a/cpukit/libfs/src/dosfs/fat.c b/cpukit/libfs/src/dosfs/fat.c
new file mode 100644
index 0000000000..852c104781
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/fat.c
@@ -0,0 +1,695 @@
+/*
+ * fat.c
+ *
+ * Low-level operations on a volume with FAT filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+
+/* _fat_block_read --
+ * This function reads 'count' bytes from device filesystem is mounted on,
+ * starts at 'start+offset' position where 'start' computed in sectors
+ * and 'offset' is offset inside sector (reading may cross sectors
+ * boundary; in this case assumed we want to read sequential sector(s))
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start - sector num to start read from
+ * offset - offset inside sector 'start'
+ * count - count of bytes to read
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes read on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+_fat_block_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ void *buff
+ )
+{
+ int rc = RC_OK;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ ssize_t cmpltd = 0;
+ unsigned32 blk = start;
+ unsigned32 ofs = offset;
+ bdbuf_buffer *block = NULL;
+ unsigned32 c = 0;
+
+ while (count > 0)
+ {
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ if (rc != RC_OK)
+ return rc;
+
+ c = MIN(count, (fs_info->vol.bps - ofs));
+ memcpy((buff + cmpltd), (block->buffer + ofs), c);
+
+ count -= c;
+ cmpltd += c;
+ blk++;
+ ofs = 0;
+ }
+ return cmpltd;
+}
+
+/* _fat_block_write --
+ * This function write 'count' bytes to device filesystem is mounted on,
+ * starts at 'start+offset' position where 'start' computed in sectors
+ * and 'offset' is offset inside sector (writing may cross sectors
+ * boundary; in this case assumed we want to write sequential sector(s))
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start - sector num to start read from
+ * offset - offset inside sector 'start'
+ * count - count of bytes to write
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+_fat_block_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ const void *buff)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ ssize_t cmpltd = 0;
+ unsigned32 blk = start;
+ unsigned32 ofs = offset;
+ bdbuf_buffer *block = NULL;
+ unsigned32 c = 0;
+
+ while(count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bps - ofs));
+
+ if (c == fs_info->vol.bps)
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
+ else
+ rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
+ if (rc != RC_OK)
+ return rc;
+
+ memcpy((block->buffer + ofs), (buff + cmpltd), c);
+
+ fat_buf_mark_modified(fs_info);
+
+ count -= c;
+ cmpltd +=c;
+ blk++;
+ ofs = 0;
+ }
+ return cmpltd;
+}
+
+
+
+
+/* fat_cluster_read --
+ * wrapper for reading a whole cluster at once
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to read
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes read on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+fat_cluster_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ void *buff
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 fsec = 0;
+
+ fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
+
+ return _fat_block_read(mt_entry, fsec, 0,
+ fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+}
+
+/* fat_cluster_write --
+ * wrapper for writting a whole cluster at once
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to write
+ * buff - buffer provided by user
+ *
+ * RETURNS:
+ * bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+fat_cluster_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ const void *buff
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 fsec = 0;
+
+ fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
+
+ return _fat_block_write(mt_entry, fsec, 0,
+ fs_info->vol.spc << fs_info->vol.sec_log2, buff);
+}
+
+/* fat_init_volume_info --
+ * Get inforamtion about volume on which filesystem is mounted on
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ register fat_vol_t *vol = &fs_info->vol;
+ unsigned32 data_secs = 0;
+ char boot_rec[FAT_MAX_BPB_SIZE];
+ char fs_info_sector[FAT_USEFUL_INFO_SIZE];
+ ssize_t ret = 0;
+ int fd;
+ struct stat stat_buf;
+ int i = 0;
+
+ rc = stat(mt_entry->dev, &stat_buf);
+ if (rc == -1)
+ return rc;
+
+ /* rtmes feature: no block devices, all are character devices */
+ if (!S_ISCHR(stat_buf.st_mode))
+ set_errno_and_return_minus_one(ENOTBLK);
+
+ /* check that device is registred as block device and lock it */
+ vol->dd = rtems_disk_lookup(stat_buf.st_dev);
+ if (vol->dd == NULL)
+ set_errno_and_return_minus_one(ENOTBLK);
+
+ vol->dev = stat_buf.st_dev;
+
+ fd = open(mt_entry->dev, O_RDONLY);
+ if (fd == -1)
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ ret = read(fd, (void *)boot_rec, FAT_MAX_BPB_SIZE);
+ if ( ret != FAT_MAX_BPB_SIZE )
+ {
+ close(fd);
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EIO );
+ }
+ close(fd);
+
+ vol->bps = FAT_BR_BYTES_PER_SECTOR(boot_rec);
+
+ if ( (vol->bps != 512) &&
+ (vol->bps != 1024) &&
+ (vol->bps != 2048) &&
+ (vol->bps != 4096))
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+
+ for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
+ i >>= 1, vol->sec_mul++);
+ for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
+ i >>= 1, vol->sec_log2++);
+
+ vol->spc = FAT_BR_SECTORS_PER_CLUSTER(boot_rec);
+ for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
+ i >>= 1, vol->spc_log2++);
+
+ /*
+ * According to M$ White Paper "bytes per cluster" value
+ * greater than 32K is invalid
+ */
+ if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one(EINVAL);
+ }
+
+ for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
+ i >>= 1, vol->bpc_log2++);
+
+ vol->fats = FAT_BR_FAT_NUM(boot_rec);
+ vol->fat_loc = FAT_BR_RESERVED_SECTORS_NUM(boot_rec);
+
+ vol->rdir_entrs = FAT_BR_FILES_PER_ROOT_DIR(boot_rec);
+
+ /* calculate the count of sectors occupied by the root directory */
+ vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
+ vol->bps;
+
+ vol->rdir_size = vol->rdir_secs << vol->sec_log2;
+
+ if ( (FAT_BR_SECTORS_PER_FAT(boot_rec)) != 0)
+ vol->fat_length = FAT_BR_SECTORS_PER_FAT(boot_rec);
+ else
+ vol->fat_length = FAT_BR_SECTORS_PER_FAT32(boot_rec);
+
+ vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
+ vol->rdir_secs;
+
+ /* for FAT12/16 root dir starts at(sector) */
+ vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
+
+ if ( (FAT_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
+ vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM16(boot_rec);
+ else
+ vol->tot_secs = FAT_BR_TOTAL_SECTORS_NUM32(boot_rec);
+
+ data_secs = vol->tot_secs - vol->data_fsec;
+
+ vol->data_cls = data_secs / vol->spc;
+
+ /* determine FAT type at least */
+ if ( vol->data_cls < FAT_FAT12_MAX_CLN)
+ {
+ vol->type = FAT_FAT12;
+ vol->mask = FAT_FAT12_MASK;
+ vol->eoc_val = FAT_FAT12_EOC;
+ }
+ else
+ {
+ if ( vol->data_cls < FAT_FAT16_MAX_CLN)
+ {
+ vol->type = FAT_FAT16;
+ vol->mask = FAT_FAT16_MASK;
+ vol->eoc_val = FAT_FAT16_EOC;
+ }
+ else
+ {
+ vol->type = FAT_FAT32;
+ vol->mask = FAT_FAT32_MASK;
+ vol->eoc_val = FAT_FAT32_EOC;
+ }
+ }
+
+ if (vol->type == FAT_FAT32)
+ {
+ vol->rdir_cl = FAT_BR_FAT32_ROOT_CLUSTER(boot_rec);
+
+ vol->mirror = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
+ if (vol->mirror)
+ vol->afat = FAT_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
+ else
+ vol->afat = 0;
+
+ vol->info_sec = FAT_BR_FAT32_FS_INFO_SECTOR(boot_rec);
+ if( vol->info_sec == 0 )
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+ else
+ {
+ ret = _fat_block_read(mt_entry, vol->info_sec , 0,
+ FAT_FSI_LEADSIG_SIZE, fs_info_sector);
+ if ( ret < 0 )
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ if (FAT_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
+ FAT_FSINFO_LEAD_SIGNATURE_VALUE)
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( EINVAL );
+ }
+ else
+ {
+ ret = _fat_block_read(mt_entry, vol->info_sec , FAT_FSI_INFO,
+ FAT_USEFUL_INFO_SIZE, fs_info_sector);
+ if ( ret < 0 )
+ {
+ rtems_disk_release(vol->dd);
+ return -1;
+ }
+
+ vol->free_cls = FAT_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
+ vol->next_cl = FAT_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
+ rc = fat_fat32_update_fsinfo_sector(mt_entry, 0xFFFFFFFF,
+ 0xFFFFFFFF);
+ if ( rc != RC_OK )
+ {
+ rtems_disk_release(vol->dd);
+ return rc;
+ }
+ }
+ }
+ }
+ else
+ {
+ vol->rdir_cl = 0;
+ vol->mirror = 0;
+ vol->afat = 0;
+ vol->free_cls = 0xFFFFFFFF;
+ vol->next_cl = 0xFFFFFFFF;
+ }
+ vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
+
+ /* set up collection of fat-files fd */
+ fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
+ if ( fs_info->vhash == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ _Chain_Initialize_empty(fs_info->vhash + i);
+
+ fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(Chain_Control));
+ if ( fs_info->rhash == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ _Chain_Initialize_empty(fs_info->rhash + i);
+
+ fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
+ fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
+ fs_info->index = 0;
+ fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
+ if ( fs_info->uino == NULL )
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ fs_info->sec_buf = (char *)calloc(vol->bps, sizeof(char));
+ if (fs_info->sec_buf == NULL)
+ {
+ rtems_disk_release(vol->dd);
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+ free(fs_info->uino);
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+
+ return RC_OK;
+}
+
+/* fat_shutdown_drive --
+ * Free all allocated resources and synchronize all necessary data
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ int i = 0;
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ rc = fat_fat32_update_fsinfo_sector(mt_entry, fs_info->vol.free_cls,
+ fs_info->vol.next_cl);
+ if ( rc != RC_OK )
+ rc = -1;
+ }
+
+ fat_buf_release(fs_info);
+
+ if (rtems_bdbuf_syncdev(fs_info->vol.dev) != RTEMS_SUCCESSFUL)
+ rc = -1;
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ {
+ Chain_Node *node = NULL;
+ Chain_Control *the_chain = fs_info->vhash + i;
+
+ while ( (node = _Chain_Get(the_chain)) != NULL )
+ free(node);
+ }
+
+ for (i = 0; i < FAT_HASH_SIZE; i++)
+ {
+ Chain_Node *node = NULL;
+ Chain_Control *the_chain = fs_info->rhash + i;
+
+ while ( (node = _Chain_Get(the_chain)) != NULL )
+ free(node);
+ }
+
+ free(fs_info->vhash);
+ free(fs_info->rhash);
+
+ free(fs_info->uino);
+ free(fs_info->sec_buf);
+ rtems_disk_release(fs_info->vol.dd);
+
+ if (rc)
+ errno = EIO;
+ return rc;
+}
+
+/* fat_init_clusters_chain --
+ * Zeroing contents of all clusters in the chain
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * start_cluster_num - num of first cluster in the chain
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_init_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start_cln
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = start_cln;
+ char *buf;
+
+ buf = calloc(fs_info->vol.bpc, sizeof(char));
+ if ( buf == NULL )
+ set_errno_and_return_minus_one( EIO );
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ ret = fat_cluster_write(mt_entry, cur_cln, buf);
+ if ( ret == -1 )
+ {
+ free(buf);
+ return -1;
+ }
+
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ {
+ free(buf);
+ return rc;
+ }
+
+ }
+ free(buf);
+ return rc;
+}
+
+#define FAT_UNIQ_INO_BASE 0x0FFFFF00
+
+#define FAT_UNIQ_INO_IS_BUSY(index, arr) \
+ (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
+
+#define FAT_SET_UNIQ_INO_BUSY(index, arr) \
+ ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
+
+#define FAT_SET_UNIQ_INO_FREE(index, arr) \
+ ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
+
+/* fat_get_unique_ino --
+ * Allocate unique ino from unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * unique inode number on success, or 0 if there is no free unique inode
+ * number in the pool
+ *
+ * ATTENTION:
+ * 0 means FAILED !!!
+ *
+ */
+unsigned32
+fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry)
+{
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0;
+ rtems_boolean resrc_unsuff = FALSE;
+
+ while (!resrc_unsuff)
+ {
+ for (j = 0; j < fs_info->uino_pool_size; j++)
+ {
+ if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
+ {
+ FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
+ return (fs_info->uino_base + fs_info->index);
+ }
+ fs_info->index++;
+ if (fs_info->index >= fs_info->uino_pool_size)
+ fs_info->index = 0;
+ }
+
+ if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
+ {
+ fs_info->uino_pool_size <<= 1;
+ fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
+ if (fs_info->uino != NULL)
+ fs_info->index = fs_info->uino_pool_size;
+ else
+ resrc_unsuff = TRUE;
+ }
+ else
+ resrc_unsuff = TRUE;
+ }
+ return 0;
+}
+
+/* fat_free_unique_ino --
+ * Return unique ino to unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * ino - inode number to free
+ *
+ * RETURNS:
+ * None
+ */
+void
+fat_free_unique_ino(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
+}
+
+/* fat_ino_is_unique --
+ * Test whether ino is from unique ino pool
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * ino - ino to be tested
+ *
+ * RETURNS:
+ * TRUE if ino is allocated from unique ino pool, FALSE otherwise
+ */
+inline rtems_boolean
+fat_ino_is_unique(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ return (ino >= fs_info->uino_base);
+}
+
+/* fat_fat32_update_fsinfo_sector --
+ * Synchronize fsinfo sector for FAT32 volumes
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * free_count - count of free clusters
+ * next_free - the next free cluster num
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_fat32_update_fsinfo_sector(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 free_count,
+ unsigned32 next_free
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_free_count = 0;
+ unsigned32 le_next_free = 0;
+
+ le_free_count = CT_LE_L(free_count);
+ le_next_free = CT_LE_L(next_free);
+
+ ret1 = _fat_block_write(mt_entry,
+ fs_info->vol.info_sec,
+ FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
+ 4,
+ (char *)(&le_free_count));
+
+ ret2 = _fat_block_write(mt_entry,
+ fs_info->vol.info_sec,
+ FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
+ 4,
+ (char *)(&le_next_free));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+ \ No newline at end of file
diff --git a/cpukit/libfs/src/dosfs/fat.h b/cpukit/libfs/src/dosfs/fat.h
new file mode 100644
index 0000000000..04a1f0f662
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/fat.h
@@ -0,0 +1,489 @@
+/*
+ * fat.h
+ *
+ * Constants/data structures/prototypes for low-level operations on a volume
+ * with FAT filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#ifndef __DOSFS_FAT_H__
+#define __DOSFS_FAT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems/seterr.h>
+
+/* XXX: temporary hack :(( */
+#ifndef set_errno_and_return_minus_one
+#define set_errno_and_return_minus_one rtems_set_errno_and_return_minus_one
+#endif /* set_errno_and_return_minus_one */
+
+#include <rtems/score/cpu.h>
+#include <errno.h>
+#include <rtems/bdbuf.h>
+
+#define DBG1(x) x
+#define DBG2(x) x
+
+#ifndef RC_OK
+#define RC_OK 0x00000000
+#endif
+
+/*
+ * Remember that all FAT file system on disk data structure is
+ * "little endian"!
+ * (derived from linux)
+ */
+/*
+ * Conversion from and to little-endian byte order. (no-op on i386/i486)
+ *
+ * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian,
+ * BE = big-endian, c: W = word (16 bits), L = longword (32 bits)
+ */
+
+#if (CPU_BIG_ENDIAN == TRUE)
+# define CF_LE_W(v) CPU_swap_u16(v)
+# define CF_LE_L(v) CPU_swap_u32(v)
+# define CT_LE_W(v) CPU_swap_u16(v)
+# define CT_LE_L(v) CPU_swap_u32(v)
+#else
+# define CF_LE_W(v) (v)
+# define CF_LE_L(v) (v)
+# define CT_LE_W(v) (v)
+# define CT_LE_L(v) (v)
+#endif
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+#define FAT_HASH_SIZE 2
+#define FAT_HASH_MODULE FAT_HASH_SIZE
+
+
+#define FAT_SECTOR512_SIZE 512 /* sector size (bytes) */
+#define FAT_SECTOR512_BITS 9 /* log2(SECTOR_SIZE) */
+
+/* maximum + 1 number of clusters for FAT12 */
+#define FAT_FAT12_MAX_CLN 4085
+
+/* maximum + 1 number of clusters for FAT16 */
+#define FAT_FAT16_MAX_CLN 65525
+
+#define FAT_FAT12 0x01
+#define FAT_FAT16 0x02
+#define FAT_FAT32 0x04
+
+#define FAT_UNDEFINED_VALUE 0xFFFFFFFF
+
+#define FAT_FAT12_EOC 0x0FFF
+#define FAT_FAT16_EOC 0xFFFF
+#define FAT_FAT32_EOC 0x0FFFFFFF
+
+#define FAT_FAT12_FREE 0x0000
+#define FAT_FAT16_FREE 0x0000
+#define FAT_FAT32_FREE 0x00000000
+
+#define FAT_GENFAT_EOC 0xFFFFFFFF
+#define FAT_GENFAT_FREE 0x00000000
+
+#define FAT_FAT12_SHIFT 0x04
+
+#define FAT_FAT12_MASK 0x00000FFF
+#define FAT_FAT16_MASK 0x0000FFFF
+#define FAT_FAT32_MASK 0x0FFFFFFF
+
+#define FAT_MAX_BPB_SIZE 90
+
+/* size of useful information in FSInfo sector */
+#define FAT_USEFUL_INFO_SIZE 12
+
+#define FAT_VAL8(x, ofs) (unsigned8)(*((unsigned8 *)(x) + (ofs)))
+
+#define FAT_VAL16(x, ofs) \
+ (unsigned16)( (*((unsigned8 *)(x) + (ofs))) | \
+ ((*((unsigned8 *)(x) + (ofs) + 1)) << 8) )
+
+#define FAT_VAL32(x, ofs) \
+ (unsigned32)( (*((unsigned8 *)(x) + (ofs))) | \
+ ((*((unsigned8 *)(x) + (ofs) + 1)) << 8) | \
+ ((*((unsigned8 *)(x) + (ofs) + 2)) << 16) | \
+ ((*((unsigned8 *)(x) + (ofs) + 3)) << 24) )
+
+/* macros to access boot sector fields */
+#define FAT_BR_BYTES_PER_SECTOR(x) FAT_VAL16(x, 11)
+#define FAT_BR_SECTORS_PER_CLUSTER(x) FAT_VAL8(x, 13)
+#define FAT_BR_RESERVED_SECTORS_NUM(x) FAT_VAL16(x, 14)
+#define FAT_BR_FAT_NUM(x) FAT_VAL8(x, 16)
+#define FAT_BR_FILES_PER_ROOT_DIR(x) FAT_VAL16(x, 17)
+#define FAT_BR_TOTAL_SECTORS_NUM16(x) FAT_VAL16(x, 19)
+#define FAT_BR_MEDIA(x) FAT_VAL8(x, 21)
+#define FAT_BR_SECTORS_PER_FAT(x) FAT_VAL16(x, 22)
+#define FAT_BR_TOTAL_SECTORS_NUM32(x) FAT_VAL32(x, 32)
+#define FAT_BR_SECTORS_PER_FAT32(x) FAT_VAL32(x, 36)
+#define FAT_BR_EXT_FLAGS(x) FAT_VAL16(x, 40)
+#define FAT_BR_FAT32_ROOT_CLUSTER(x) FAT_VAL32(x, 44)
+#define FAT_BR_FAT32_FS_INFO_SECTOR(x) FAT_VAL16(x, 48)
+#define FAT_FSINFO_LEAD_SIGNATURE(x) FAT_VAL32(x, 0)
+/*
+ * I read FSInfo sector from offset 484 to access the information, so offsets
+ * of these fields a relative
+ */
+#define FAT_FSINFO_FREE_CLUSTER_COUNT(x) FAT_VAL32(x, 4)
+#define FAT_FSINFO_NEXT_FREE_CLUSTER(x) FAT_VAL32(x, 8)
+
+#define FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET 488
+
+#define FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET 492
+
+#define FAT_RSRVD_CLN 0x02
+
+#define FAT_FSINFO_LEAD_SIGNATURE_VALUE 0x41615252
+
+#define FAT_FSI_LEADSIG_SIZE 0x04
+
+#define FAT_FSI_INFO 484
+
+#define MS_BYTES_PER_CLUSTER_LIMIT 0x8000 /* 32K */
+
+#define FAT_BR_EXT_FLAGS_MIRROR 0x0080
+
+#define FAT_BR_EXT_FLAGS_FAT_NUM 0x000F
+
+
+#define FAT_DIRENTRY_SIZE 32
+
+#define FAT_DIRENTRIES_PER_SEC512 16
+
+/*
+ * Volume descriptor
+ * Description of the volume the FAT filesystem is located on - generally
+ * the fields of the structure corresponde to Boot Sector and BPB Srtucture
+ * (see M$ White Paper) fields
+ */
+typedef struct fat_vol_s
+{
+ unsigned16 bps; /* bytes per sector */
+ unsigned8 sec_log2; /* log2 of bps */
+ unsigned8 sec_mul; /* log2 of 512bts sectors number per sector */
+ unsigned8 spc; /* sectors per cluster */
+ unsigned8 spc_log2; /* log2 of spc */
+ unsigned16 bpc; /* bytes per cluster */
+ unsigned8 bpc_log2; /* log2 of bytes per cluster */
+ unsigned8 fats; /* number of FATs */
+ unsigned8 type; /* FAT type */
+ unsigned32 mask;
+ unsigned32 eoc_val;
+ unsigned16 fat_loc; /* FAT start */
+ unsigned32 fat_length; /* sectors per FAT */
+ unsigned32 rdir_loc; /* root directory start */
+ unsigned16 rdir_entrs; /* files per root directory */
+ unsigned32 rdir_secs; /* sectors per root directory */
+ unsigned32 rdir_size; /* root directory size in bytes */
+ unsigned32 tot_secs; /* total count of sectors */
+ unsigned32 data_fsec; /* first data sector */
+ unsigned32 data_cls; /* count of data clusters */
+ unsigned32 rdir_cl; /* first cluster of the root directory */
+ unsigned16 info_sec; /* FSInfo Sector Structure location */
+ unsigned32 free_cls; /* last known free clusters count */
+ unsigned32 next_cl; /* next free cluster number */
+ unsigned8 mirror; /* mirroring enabla/disable */
+ unsigned32 afat_loc; /* active FAT location */
+ unsigned8 afat; /* the number of active FAT */
+ dev_t dev; /* device ID */
+ disk_device *dd; /* disk device (see libblock) */
+ void *private_data; /* reserved */
+} fat_vol_t;
+
+
+typedef struct fat_cache_s
+{
+ unsigned32 blk_num;
+ rtems_boolean modified;
+ unsigned8 state;
+ bdbuf_buffer *buf;
+} fat_cache_t;
+
+/*
+ * This structure identifies the instance of the filesystem on the FAT
+ * ("fat-file") level.
+ */
+typedef struct fat_fs_info_s
+{
+ fat_vol_t vol; /* volume descriptor */
+ Chain_Control *vhash; /* "vhash" of fat-file descriptors */
+ Chain_Control *rhash; /* "rhash" of fat-file descriptors */
+ char *uino; /* array of unique ino numbers */
+ unsigned32 index;
+ unsigned32 uino_pool_size; /* size */
+ unsigned32 uino_base;
+ fat_cache_t c; /* cache */
+ unsigned8 *sec_buf; /* just placeholder for anything */
+} fat_fs_info_t;
+
+/*
+ * if the name we looking for is file we store not only first data cluster
+ * number, but and cluster number and offset for directory entry for this
+ * name
+ */
+typedef struct fat_auxiliary_s
+{
+ unsigned32 cln;
+ unsigned32 ofs;
+} fat_auxiliary_t;
+
+#define FAT_FAT_OFFSET(fat_type, cln) \
+ ((fat_type) & FAT_FAT12 ? ((cln) + ((cln) >> 1)) : \
+ (fat_type) & FAT_FAT16 ? ((cln) << 1) : \
+ ((cln) << 2))
+
+#define FAT_CLUSTER_IS_ODD(n) ((n) & 0x0001)
+
+#define FAT12_SHIFT 0x4 /* half of a byte */
+
+/* initial size of array of unique ino */
+#define FAT_UINO_POOL_INIT_SIZE 0x100
+
+/* cache support */
+#define FAT_CACHE_EMPTY 0x0
+#define FAT_CACHE_ACTUAL 0x1
+
+#define FAT_OP_TYPE_READ 0x1
+#define FAT_OP_TYPE_GET 0x2
+
+static inline unsigned32
+fat_cluster_num_to_sector_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln
+ )
+{
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ if ( (cln == 0) && (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)) )
+ return fs_info->vol.rdir_loc;
+
+ return (((cln - FAT_RSRVD_CLN) << fs_info->vol.spc_log2) +
+ fs_info->vol.data_fsec);
+}
+
+static inline unsigned32
+fat_cluster_num_to_sector512_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+
+ if (cln == 1)
+ return 1;
+
+ return (fat_cluster_num_to_sector_num(mt_entry, cln) <<
+ fs_info->vol.sec_mul);
+}
+
+static inline int
+fat_buf_access(fat_fs_info_t *fs_info, unsigned32 blk, int op_type,
+ bdbuf_buffer **buf)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned8 i;
+ rtems_boolean sec_of_fat;
+
+
+ if (fs_info->c.state == FAT_CACHE_EMPTY)
+ {
+ if (op_type == FAT_OP_TYPE_READ)
+ sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
+ else
+ sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.blk_num = blk;
+ fs_info->c.state = FAT_CACHE_ACTUAL;
+ }
+
+ sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
+ (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+
+ if (fs_info->c.blk_num != blk)
+ {
+ if (fs_info->c.modified)
+ {
+ if (sec_of_fat && !fs_info->vol.mirror)
+ memcpy(fs_info->sec_buf, fs_info->c.buf->buffer,
+ fs_info->vol.bps);
+
+ sc = rtems_bdbuf_release_modified(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.modified = 0;
+
+ if (sec_of_fat && !fs_info->vol.mirror)
+ {
+ bdbuf_buffer *b;
+
+ for (i = 1; i < fs_info->vol.fats; i++)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dev,
+ fs_info->c.blk_num +
+ fs_info->vol.fat_length * i,
+ &b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+ }
+ }
+ else
+ {
+ sc = rtems_bdbuf_release(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ }
+ if (op_type == FAT_OP_TYPE_READ)
+ sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
+ else
+ sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.blk_num = blk;
+ }
+ *buf = fs_info->c.buf;
+ return RC_OK;
+}
+
+
+static inline int
+fat_buf_release(fat_fs_info_t *fs_info)
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ unsigned8 i;
+ rtems_boolean sec_of_fat;
+
+ if (fs_info->c.state == FAT_CACHE_EMPTY)
+ return RC_OK;
+
+ sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
+ (fs_info->c.blk_num < fs_info->vol.rdir_loc));
+
+ if (fs_info->c.modified)
+ {
+ if (sec_of_fat && !fs_info->vol.mirror)
+ memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps);
+
+ sc = rtems_bdbuf_release_modified(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ fs_info->c.modified = 0;
+
+ if (sec_of_fat && !fs_info->vol.mirror)
+ {
+ bdbuf_buffer *b;
+
+ for (i = 1; i < fs_info->vol.fats; i++)
+ {
+ sc = rtems_bdbuf_get(fs_info->vol.dev,
+ fs_info->c.blk_num +
+ fs_info->vol.fat_length * i,
+ &b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
+ sc = rtems_bdbuf_release_modified(b);
+ if ( sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+ }
+ }
+ else
+ {
+ sc = rtems_bdbuf_release(fs_info->c.buf);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+ }
+ fs_info->c.state = FAT_CACHE_EMPTY;
+ return RC_OK;
+}
+
+static inline void
+fat_buf_mark_modified(fat_fs_info_t *fs_info)
+{
+ fs_info->c.modified = TRUE;
+}
+
+
+
+ssize_t
+_fat_block_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ void *buff);
+
+ssize_t
+_fat_block_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start,
+ unsigned32 offset,
+ unsigned32 count,
+ const void *buff);
+
+ssize_t
+fat_cluster_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ void *buff);
+
+ssize_t
+fat_cluster_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ const void *buff);
+
+int
+fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+int
+fat_init_clusters_chain(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 start_cln);
+
+unsigned32
+fat_cluster_num_to_sector_num(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln);
+
+int
+fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+
+unsigned32
+fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry);
+
+rtems_boolean
+fat_ino_is_unique(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino);
+
+void
+fat_free_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 ino);
+
+int
+fat_fat32_update_fsinfo_sector(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 free_count,
+ unsigned32 next_free
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_H__ */
diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.c b/cpukit/libfs/src/dosfs/fat_fat_operations.c
new file mode 100644
index 0000000000..49b2ab70d3
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/fat_fat_operations.c
@@ -0,0 +1,445 @@
+/*
+ * fat_fat_operations.c
+ *
+ * General operations on File Allocation Table
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+
+/* fat_scan_fat_for_free_clusters --
+ * Allocate chain of free clusters from Files Allocation Table
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * chain - the number of the first allocated cluster (first cluster
+ * in the chain)
+ * count - count of clusters to allocate (chain length)
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ *
+ */
+int
+fat_scan_fat_for_free_clusters(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 *chain,
+ unsigned32 count,
+ unsigned32 *cls_added,
+ unsigned32 *last_cl
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cl4find = 2;
+ unsigned32 next_cln = 0;
+ unsigned32 save_cln = 0;
+ unsigned32 data_cls_val = fs_info->vol.data_cls + 2;
+ unsigned32 i = 2;
+
+ *cls_added = 0;
+
+ if (count == 0)
+ return rc;
+
+ if ((fs_info->vol.type & FAT_FAT32) &&
+ (fs_info->vol.next_cl != FAT_UNDEFINED_VALUE))
+ cl4find = fs_info->vol.next_cl;
+
+ /*
+ * fs_info->vol.data_cls is exactly the count of data clusters
+ * starting at cluster 2, so the maximum valid cluster number is
+ * (fs_info->vol.data_cls + 1)
+ */
+ while (i < data_cls_val)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cl4find, &next_cln);
+ if ( rc != RC_OK )
+ {
+ if (*cls_added != 0)
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ return rc;
+ }
+
+ if ((next_cln & fs_info->vol.mask) == FAT_GENFAT_FREE)
+ {
+ /*
+ * We are enforced to process allocation of the first free cluster
+ * by separate 'if' statement because otherwise undo function
+ * wouldn't work properly
+ */
+ if (*cls_added == 0)
+ {
+ *chain = cl4find;
+ rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ {
+ /*
+ * this is the first cluster we tried to allocate so no
+ * cleanup activity needed
+ */
+ return rc;
+ }
+ }
+ else
+ {
+ /* set EOC value to new allocated cluster */
+ rc = fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ {
+ /* cleanup activity */
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ return rc;
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, save_cln, cl4find);
+ if ( rc != RC_OK )
+ {
+ /* cleanup activity */
+ fat_free_fat_clusters_chain(mt_entry, (*chain));
+ /* trying to save last allocated cluster for future use */
+ fat_set_fat_cluster(mt_entry, cl4find, FAT_GENFAT_FREE);
+ fat_buf_release(fs_info);
+ return rc;
+ }
+ }
+
+ save_cln = cl4find;
+ (*cls_added)++;
+
+ /* have we satisfied request ? */
+ if (*cls_added == count)
+ {
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = save_cln;
+ if (fs_info->vol.free_cls != 0xFFFFFFFF)
+ fs_info->vol.free_cls -= (*cls_added);
+ }
+ *last_cl = save_cln;
+ fat_buf_release(fs_info);
+ return rc;
+ }
+ }
+ i++;
+ cl4find++;
+ if (cl4find >= data_cls_val)
+ cl4find = 2;
+ }
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = save_cln;
+ if (fs_info->vol.free_cls != 0xFFFFFFFF)
+ fs_info->vol.free_cls -= (*cls_added);
+ }
+ *last_cl = save_cln;
+ fat_buf_release(fs_info);
+ return RC_OK;
+}
+
+/* fat_free_fat_clusters_chain --
+ * Free chain of clusters in Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * chain - number of the first cluster in the chain
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_free_fat_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 chain
+ )
+{
+ int rc = RC_OK, rc1 = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = chain;
+ unsigned32 next_cln = 0;
+ unsigned32 freed_cls_cnt = 0;
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &next_cln);
+ if ( rc != RC_OK )
+ {
+ if ((fs_info->vol.type & FAT_FAT32) &&
+ (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE))
+ fs_info->vol.free_cls += freed_cls_cnt;
+ fat_buf_release(fs_info);
+ return rc;
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, cur_cln, FAT_GENFAT_FREE);
+ if ( rc != RC_OK )
+ rc1 = rc;
+
+ freed_cls_cnt++;
+ cur_cln = next_cln;
+ }
+
+ if (fs_info->vol.type & FAT_FAT32)
+ {
+ fs_info->vol.next_cl = chain;
+ if (fs_info->vol.free_cls != FAT_UNDEFINED_VALUE)
+ fs_info->vol.free_cls += freed_cls_cnt;
+ }
+
+ fat_buf_release(fs_info);
+ if (rc1 != RC_OK)
+ return rc1;
+
+ return RC_OK;
+}
+
+/* fat_get_fat_cluster --
+ * Fetches the contents of the cluster (link to next cluster in the chain)
+ * from Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to fetch the contents from
+ * ret_val - contents of the cluster 'cln' (link to next cluster in
+ * the chain)
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_get_fat_cluster(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 *ret_val
+ )
+{
+ int rc = RC_OK;
+ register fat_fs_info_t *fs_info = mt_entry->fs_info;
+ bdbuf_buffer *block0 = NULL;
+ unsigned32 sec = 0;
+ unsigned32 ofs = 0;
+
+ /* sanity check */
+ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
+ set_errno_and_return_minus_one(EIO);
+
+ sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
+ fs_info->vol.afat_loc;
+ ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
+
+ rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ switch ( fs_info->vol.type )
+ {
+ case FAT_FAT12:
+ /*
+ * we are enforced in complex computations for FAT12 to escape CPU
+ * align problems for some architectures
+ */
+ *ret_val = (*((unsigned8 *)(block0->buffer + ofs)));
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *ret_val |= (*((unsigned8 *)(block0->buffer)))<<8;
+ }
+ else
+ {
+ *ret_val |= (*((unsigned8 *)(block0->buffer + ofs + 1)))<<8;
+ }
+
+ if ( FAT_CLUSTER_IS_ODD(cln) )
+ *ret_val = (*ret_val) >> FAT12_SHIFT;
+ else
+ *ret_val = (*ret_val) & FAT_FAT12_MASK;
+
+ break;
+
+ case FAT_FAT16:
+ *ret_val = *((unsigned16 *)(block0->buffer + ofs));
+ *ret_val = CF_LE_W(*ret_val);
+ break;
+
+ case FAT_FAT32:
+ *ret_val = *((unsigned32 *)(block0->buffer + ofs));
+ *ret_val = CF_LE_L(*ret_val);
+ break;
+
+ default:
+ set_errno_and_return_minus_one(EIO);
+ break;
+ }
+
+ return RC_OK;
+}
+
+/* fat_set_fat_cluster --
+ * Set the contents of the cluster (link to next cluster in the chain)
+ * from Files Allocation Table.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - number of cluster to set contents to
+ * in_val - value to set
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+fat_set_fat_cluster(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 in_val
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 ofs = 0;
+ unsigned16 fat16_clv = 0;
+ unsigned32 fat32_clv = 0;
+ bdbuf_buffer *block0 = NULL;
+
+ /* sanity check */
+ if ( (cln < 2) || (cln > (fs_info->vol.data_cls + 1)) )
+ set_errno_and_return_minus_one(EIO);
+
+ sec = (FAT_FAT_OFFSET(fs_info->vol.type, cln) >> fs_info->vol.sec_log2) +
+ fs_info->vol.afat_loc;
+ ofs = FAT_FAT_OFFSET(fs_info->vol.type, cln) & (fs_info->vol.bps - 1);
+
+ rc = fat_buf_access(fs_info, sec, FAT_OP_TYPE_READ, &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ switch ( fs_info->vol.type )
+ {
+ case FAT_FAT12:
+ if ( FAT_CLUSTER_IS_ODD(cln) )
+ {
+ fat16_clv = CT_LE_W((((unsigned16)in_val) << FAT_FAT12_SHIFT));
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) & 0x0F;
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) |
+ (unsigned8)(fat16_clv & 0x00FF);
+
+ fat_buf_mark_modified(fs_info);
+
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *((unsigned8 *)(block0->buffer)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+
+ fat_buf_mark_modified(fs_info);
+ }
+ else
+ {
+ *((unsigned8 *)(block0->buffer + ofs + 1)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer + ofs + 1)) =
+ (*((unsigned8 *)(block0->buffer + ofs + 1))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+ }
+ }
+ else
+ {
+ fat16_clv = CT_LE_W((((unsigned16)in_val) & FAT_FAT12_MASK));
+
+ *((unsigned8 *)(block0->buffer + ofs)) &= 0x00;
+
+ *((unsigned8 *)(block0->buffer + ofs)) =
+ (*((unsigned8 *)(block0->buffer + ofs))) |
+ (unsigned8)(fat16_clv & 0x00FF);
+
+ fat_buf_mark_modified(fs_info);
+
+ if ( ofs == (fs_info->vol.bps - 1) )
+ {
+ rc = fat_buf_access(fs_info, sec + 1, FAT_OP_TYPE_READ,
+ &block0);
+ if (rc != RC_OK)
+ return rc;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) & 0xF0;
+
+ *((unsigned8 *)(block0->buffer)) =
+ (*((unsigned8 *)(block0->buffer))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+
+ fat_buf_mark_modified(fs_info);
+ }
+ else
+ {
+ *((unsigned8 *)(block0->buffer + ofs + 1)) =
+ (*((unsigned8 *)(block0->buffer + ofs + 1))) & 0xF0;
+
+ *((unsigned8 *)(block0->buffer + ofs+1)) =
+ (*((unsigned8 *)(block0->buffer + ofs+1))) |
+ (unsigned8)((fat16_clv & 0xFF00)>>8);
+ }
+ }
+ break;
+
+ case FAT_FAT16:
+ *((unsigned16 *)(block0->buffer + ofs)) =
+ (unsigned16)(CT_LE_W(in_val));
+ fat_buf_mark_modified(fs_info);
+ break;
+
+ case FAT_FAT32:
+ fat32_clv = CT_LE_L((in_val & FAT_FAT32_MASK));
+
+ *((unsigned32 *)(block0->buffer + ofs)) =
+ (*((unsigned32 *)(block0->buffer + ofs))) & (CT_LE_L(0xF0000000));
+
+ *((unsigned32 *)(block0->buffer + ofs)) =
+ fat32_clv | (*((unsigned32 *)(block0->buffer + ofs)));
+
+ fat_buf_mark_modified(fs_info);
+ break;
+
+ default:
+ set_errno_and_return_minus_one(EIO);
+ break;
+
+ }
+
+ return RC_OK;
+}
diff --git a/cpukit/libfs/src/dosfs/fat_fat_operations.h b/cpukit/libfs/src/dosfs/fat_fat_operations.h
new file mode 100644
index 0000000000..59b6a84018
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/fat_fat_operations.h
@@ -0,0 +1,58 @@
+/*
+ * fat_fat_operations.h
+ *
+ * Constants/data structures/prototypes for operations on Files Allocation
+ * Table
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_FAT_FAT_OPERATIONS_H__
+#define __DOSFS_FAT_FAT_OPERATIONS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <rtems/bdbuf.h>
+#include "fat.h"
+
+int
+fat_get_fat_cluster(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 *ret_val);
+
+int
+fat_set_fat_cluster(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 in_val);
+
+int
+fat_scan_fat_for_free_clusters(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 *chain,
+ unsigned32 count,
+ unsigned32 *cls_added,
+ unsigned32 *last_cl
+);
+
+int
+fat_free_fat_clusters_chain(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 chain
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_FAT_OPERATIONS_H__ */
diff --git a/cpukit/libfs/src/dosfs/fat_file.c b/cpukit/libfs/src/dosfs/fat_file.c
new file mode 100644
index 0000000000..4fd8a5024f
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/fat_file.c
@@ -0,0 +1,979 @@
+/*
+ * fat_file.c
+ *
+ * General operations on "fat-file"
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * @(#) $Id$
+ *
+ */
+
+#include <bsp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <time.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+static inline void
+_hash_insert(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el);
+
+static inline void
+_hash_delete(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el);
+
+static inline int
+_hash_search(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ Chain_Control *hash,
+ unsigned32 key1,
+ unsigned32 key2,
+ void **ret
+);
+
+static int
+fat_file_lseek(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 file_cln,
+ unsigned32 *disk_cln
+);
+
+/* fat_file_open --
+ * Open fat-file. Two hash tables are accessed by key
+ * constructed from cluster num and offset of the node (i.e.
+ * files/directories are distinguished by location on the disk).
+ * First, hash table("vhash") consists of fat-file descriptors corresponded
+ * to "valid" files is accessed. Search is made by 2 fields equal to key
+ * constructed. If descriptor is found in the "vhash" - return it.
+ * Otherwise search is made in hash table("rhash") consits of fat-file
+ * descriptors corresponded to "removed-but-still-open" files with the
+ * same keys.
+ * If search failed, new fat-file descriptor is added to "vhash"
+ * with both key fields equal to constructed key. Otherwise new fat-file
+ * descriptor is added to "vhash" with first key field equal to key
+ * constructed and the second equal to an unique (unique among all values
+ * of second key fields) value.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - cluster num of the node
+ * ofs - offset of the node
+ * fat_fd - placeholder for returned fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK and pointer to opened descriptor on success, or -1 if error
+ * occured (errno set appropriately)
+ */
+int
+fat_file_open(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 ofs,
+ fat_file_fd_t **fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *lfat_fd = NULL;
+ unsigned32 key = 0;
+
+ /* construct key */
+ key = fat_construct_key(mt_entry, cln, ofs);
+
+ /* access "valid" hash table */
+ rc = _hash_search(mt_entry, fs_info->vhash, key, 0, (void **)&lfat_fd);
+ if ( rc == RC_OK )
+ {
+ /* return pointer to fat_file_descriptor allocated before */
+ (*fat_fd) = lfat_fd;
+ lfat_fd->links_num++;
+ return rc;
+ }
+
+ /* access "removed-but-still-open" hash table */
+ rc = _hash_search(mt_entry, fs_info->rhash, key, key, (void **)&lfat_fd);
+
+ lfat_fd = (*fat_fd) = (fat_file_fd_t*)malloc(sizeof(fat_file_fd_t));
+ if ( lfat_fd == NULL )
+ set_errno_and_return_minus_one( ENOMEM );
+
+ lfat_fd->links_num = 1;
+ lfat_fd->flags &= ~FAT_FILE_REMOVED;
+ lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+
+ if ( rc != RC_OK )
+ lfat_fd->ino = key;
+ else
+ {
+ lfat_fd->ino = fat_get_unique_ino(mt_entry);
+
+ if ( lfat_fd->ino == 0 )
+ {
+ free((*fat_fd));
+ /*
+ * XXX: kernel resource is unsufficient, but not the memory,
+ * but there is no suitable errno :(
+ */
+ set_errno_and_return_minus_one( ENOMEM );
+ }
+ }
+ _hash_insert(fs_info->vhash, key, lfat_fd->ino, lfat_fd);
+
+
+ /*
+ * other fields of fat-file descriptor will be initialized on upper
+ * level
+ */
+
+ return RC_OK;
+}
+
+
+/* fat_file_reopen --
+ * Increment by 1 number of links
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK
+ */
+int
+fat_file_reopen(fat_file_fd_t *fat_fd)
+{
+ fat_fd->links_num++;
+ return RC_OK;
+}
+
+/* fat_file_close --
+ * Close fat-file. If count of links to fat-file
+ * descriptor is greater than 1 (i.e. somebody esle holds pointer
+ * to this descriptor) just decrement it. Otherwise
+ * do the following. If this descriptor corresponded to removed fat-file
+ * then free clusters contained fat-file data, delete descriptor from
+ * "rhash" table and free memory allocated by descriptor. If descriptor
+ * correspondes to non-removed fat-file and 'ino' field has value from
+ * unique inode numbers pool then set count of links to descriptor to zero
+ * and leave it in hash, otherwise delete descriptor from "vhash" and free
+ * memory allocated by the descriptor
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_close(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 key = 0;
+
+ /*
+ * if links_num field of fat-file descriptor is greater than 1
+ * decrement the count of links and return
+ */
+ if (fat_fd->links_num > 1)
+ {
+ fat_fd->links_num--;
+ return rc;
+ }
+
+ key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs);
+
+ if (fat_fd->flags & FAT_FILE_REMOVED)
+ {
+ rc = fat_file_truncate(mt_entry, fat_fd, 0);
+ if ( rc != RC_OK )
+ return rc;
+
+ _hash_delete(fs_info->rhash, key, fat_fd->ino, fat_fd);
+
+ if ( fat_ino_is_unique(mt_entry, fat_fd->ino) )
+ fat_free_unique_ino(mt_entry, fat_fd->ino);
+
+ free(fat_fd);
+ }
+ else
+ {
+ if (fat_ino_is_unique(mt_entry, fat_fd->ino))
+ {
+ fat_fd->links_num = 0;
+ }
+ else
+ {
+ _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
+ free(fat_fd);
+ }
+ }
+ return rc;
+}
+
+/* fat_file_read --
+ * Read 'count' bytes from 'start' position from fat-file. This
+ * interface hides the architecture of fat-file, represents it as
+ * linear file
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * start - offset in fat-file (in bytes) to read from
+ * count - count of bytes to read
+ * buf - buffer provided by user
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno
+ * set appropriately)
+ */
+ssize_t
+fat_file_read(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cmpltd = 0;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 save_cln = 0;
+ unsigned32 ofs = 0;
+ unsigned32 save_ofs;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+ unsigned32 c = 0;
+
+ /* it couldn't be removed - otherwise cache update will be broken */
+ if (count == 0)
+ return cmpltd;
+
+ /*
+ * >= because start is offset and computed from 0 and file_size
+ * computed from 1
+ */
+ if ( start >= fat_fd->fat_file_size )
+ return FAT_EOF;
+
+ if ((count > fat_fd->fat_file_size) ||
+ (start > fat_fd->fat_file_size - count))
+ count = fat_fd->fat_file_size - start;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
+ sec += (start >> fs_info->vol.sec_log2);
+ byte = start & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_read(mt_entry, sec, byte, count, buf);
+ if ( ret < 0 )
+ return -1;
+
+ return ret;
+ }
+
+ cl_start = start >> fs_info->vol.bpc_log2;
+ save_ofs = ofs = start & (fs_info->vol.bpc - 1);
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ while (count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bpc - ofs));
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ sec += (ofs >> fs_info->vol.sec_log2);
+ byte = ofs & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_read(mt_entry, sec, byte, c, buf + cmpltd);
+ if ( ret < 0 )
+ return -1;
+
+ count -= c;
+ cmpltd += c;
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ ofs = 0;
+ }
+
+ /* update cache */
+ /* XXX: check this - I'm not sure :( */
+ fat_fd->map.file_cln = cl_start +
+ ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
+ fat_fd->map.disk_cln = save_cln;
+
+ return cmpltd;
+}
+
+/* fat_file_write --
+ * Write 'count' bytes of data from user supplied buffer to fat-file
+ * starting at offset 'start'. This interface hides the architecture
+ * of fat-file, represents it as linear file
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * start - offset(in bytes) to write from
+ * count - count
+ * buf - buffer provided by user
+ *
+ * RETURNS:
+ * number of bytes actually written to the file on success, or -1 if
+ * error occured (errno set appropriately)
+ */
+ssize_t
+fat_file_write(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf
+ )
+{
+ int rc = 0;
+ ssize_t ret = 0;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cmpltd = 0;
+ unsigned32 cur_cln = 0;
+ unsigned32 save_cln;
+ unsigned32 cl_start = 0;
+ unsigned32 ofs = 0;
+ unsigned32 save_ofs;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+ unsigned32 c = 0;
+
+ if ( count == 0 )
+ return cmpltd;
+
+ if ( start > fat_fd->fat_file_size )
+ set_errno_and_return_minus_one( EIO );
+
+ if ((count > fat_fd->size_limit) ||
+ (start > fat_fd->size_limit - count))
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_extend(mt_entry, fat_fd, start + count, &c);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * check whether there was enough room on device to locate
+ * file of 'start + count' bytes
+ */
+ if (c != (start + count))
+ count = c - start;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
+ sec += (start >> fs_info->vol.sec_log2);
+ byte = start & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_write(mt_entry, sec, byte, count, buf);
+ if ( ret < 0 )
+ return -1;
+
+ return ret;
+ }
+
+ cl_start = start >> fs_info->vol.bpc_log2;
+ save_ofs = ofs = start & (fs_info->vol.bpc - 1);
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ while (count > 0)
+ {
+ c = MIN(count, (fs_info->vol.bpc - ofs));
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ sec += (ofs >> fs_info->vol.sec_log2);
+ byte = ofs & (fs_info->vol.bps - 1);
+
+ ret = _fat_block_write(mt_entry, sec, byte, c, buf + cmpltd);
+ if ( ret < 0 )
+ return -1;
+
+ count -= c;
+ cmpltd += c;
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ ofs = 0;
+ }
+
+ /* update cache */
+ /* XXX: check this - I'm not sure :( */
+ fat_fd->map.file_cln = cl_start +
+ ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
+ fat_fd->map.disk_cln = save_cln;
+
+ return cmpltd;
+}
+
+/* fat_file_extend --
+ * Extend fat-file. If new length less than current fat-file size -
+ * do nothing. Otherwise calculate necessary count of clusters to add,
+ * allocate it and add new clusters chain to the end of
+ * existing clusters chain.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * new_length - new length
+ * a_length - placeholder for result - actual new length of file
+ *
+ * RETURNS:
+ * RC_OK and new length of file on success, or -1 if error occured (errno
+ * set appropriately)
+ */
+int
+fat_file_extend(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length,
+ unsigned32 *a_length
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 chain = 0;
+ unsigned32 bytes2add = 0;
+ unsigned32 cls2add = 0;
+ unsigned32 old_last_cl;
+ unsigned32 last_cl = 0;
+ unsigned32 bytes_remain = 0;
+ unsigned32 cls_added;
+
+ *a_length = new_length;
+
+ if (new_length <= fat_fd->fat_file_size)
+ return RC_OK;
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ set_errno_and_return_minus_one( ENOSPC );
+
+ bytes_remain = (fs_info->vol.bpc -
+ (fat_fd->fat_file_size & (fs_info->vol.bpc - 1))) &
+ (fs_info->vol.bpc - 1);
+
+ bytes2add = new_length - fat_fd->fat_file_size;
+
+ if (bytes2add > bytes_remain)
+ bytes2add -= bytes_remain;
+ else
+ bytes2add = 0;
+
+ /*
+ * if in last cluster allocated for the file there is enough room to
+ * handle extention (hence we don't need to add even one cluster to the
+ * file ) - return
+ */
+ if (bytes2add == 0)
+ return RC_OK;
+
+ cls2add = ((bytes2add - 1) >> fs_info->vol.bpc_log2) + 1;
+
+ rc = fat_scan_fat_for_free_clusters(mt_entry, &chain, cls2add,
+ &cls_added, &last_cl);
+
+ /* this means that low level I/O error occured */
+ if (rc != RC_OK)
+ return rc;
+
+ /* this means that no space left on device */
+ if ((cls_added == 0) && (bytes_remain == 0))
+ set_errno_and_return_minus_one(ENOSPC);
+
+ /* check wether we satisfied request for 'cls2add' clusters */
+ if (cls2add != cls_added)
+ *a_length = new_length -
+ ((cls2add - cls_added - 1) << fs_info->vol.bpc_log2) -
+ (bytes2add & (fs_info->vol.bpc - 1));
+
+ /* add new chain to the end of existed */
+ if ( fat_fd->fat_file_size == 0 )
+ {
+ fat_fd->map.disk_cln = fat_fd->cln = chain;
+ fat_fd->map.file_cln = 0;
+ }
+ else
+ {
+ if (fat_fd->map.last_cln != FAT_UNDEFINED_VALUE)
+ {
+ old_last_cl = fat_fd->map.last_cln;
+ }
+ else
+ {
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ (fat_fd->fat_file_size - 1), &old_last_cl);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ }
+
+ rc = fat_set_fat_cluster(mt_entry, old_last_cl, chain);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ fat_buf_release(fs_info);
+ }
+
+ /* update number of the last cluster of the file if it changed */
+ if (cls_added != 0)
+ {
+ fat_fd->map.last_cln = last_cl;
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ {
+ rc = fat_init_clusters_chain(mt_entry, chain);
+ if ( rc != RC_OK )
+ {
+ fat_free_fat_clusters_chain(mt_entry, chain);
+ return rc;
+ }
+ }
+ }
+
+ return RC_OK;
+}
+
+/* fat_file_truncate --
+ * Truncate fat-file. If new length greater than current fat-file size -
+ * do nothing. Otherwise find first cluster to free and free all clusters
+ * in the chain starting from this cluster.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * new_length - new length
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_truncate(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 new_last_cln = FAT_UNDEFINED_VALUE;
+
+
+ if ( new_length >= fat_fd->fat_file_size )
+ return rc;
+
+ assert(fat_fd->fat_file_size);
+
+ cl_start = (new_length + fs_info->vol.bpc - 1) >> fs_info->vol.bpc_log2;
+
+ if ((cl_start << fs_info->vol.bpc_log2) >= fat_fd->fat_file_size)
+ return RC_OK;
+
+ if (cl_start != 0)
+ {
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start - 1, &new_last_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ }
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ rc = fat_free_fat_clusters_chain(mt_entry, cur_cln);
+ if (rc != RC_OK)
+ return rc;
+
+ if (cl_start != 0)
+ {
+ rc = fat_set_fat_cluster(mt_entry, new_last_cln, FAT_GENFAT_EOC);
+ if ( rc != RC_OK )
+ return rc;
+ fat_fd->map.file_cln = cl_start - 1;
+ fat_fd->map.disk_cln = new_last_cln;
+ fat_fd->map.last_cln = new_last_cln;
+ }
+ return RC_OK;
+}
+
+/* fat_file_ioctl --
+ * F_CLU_NUM:
+ * make mapping between serial number of the cluster in fat-file and
+ * its real number on the volume
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ * mt_entry - mount table entry
+ * cmd - command
+ * ...
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured and errno set appropriately
+ */
+int
+fat_file_ioctl(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ int cmd,
+ ...)
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = 0;
+ unsigned32 cl_start = 0;
+ unsigned32 pos = 0;
+ unsigned32 *ret;
+ va_list ap;
+
+ va_start(ap, cmd);
+
+ switch (cmd)
+ {
+ case F_CLU_NUM:
+ pos = va_arg(ap, int);
+ ret = va_arg(ap, int *);
+
+ /* sanity check */
+ if ( pos >= fat_fd->fat_file_size )
+ set_errno_and_return_minus_one( EIO );
+
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ /* cluster 0 (zero) reserved for root dir */
+ *ret = 0;
+ return RC_OK;
+ }
+
+ cl_start = pos >> fs_info->vol.bpc_log2;
+
+ rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ *ret = cur_cln;
+ break;
+
+ default:
+ errno = EINVAL;
+ rc = -1;
+ break;
+ }
+ return rc;
+}
+
+/* fat_file_mark_removed --
+ * Remove the fat-file descriptor from "valid" hash table, insert it
+ * into "removed-but-still-open" hash table and set up "removed" bit.
+ *
+ * PARAMETERS:
+ * fat_fd - fat-file descriptor
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * None
+ */
+void
+fat_file_mark_removed(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 key = 0;
+
+ key = fat_construct_key(mt_entry, fat_fd->info_cln, fat_fd->info_ofs);
+
+ _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
+
+ _hash_insert(fs_info->rhash, key, fat_fd->ino, fat_fd);
+
+ fat_fd->flags |= FAT_FILE_REMOVED;
+}
+
+/* fat_file_datasync --
+ * Synchronize fat-file - flush all buffered data to the media.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured and errno set appropriately
+ */
+int
+fat_file_datasync(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = fat_fd->cln;
+ bdbuf_buffer *block = NULL;
+ unsigned32 sec = 0;
+ unsigned32 i = 0;
+
+ if (fat_fd->fat_file_size == 0)
+ return RC_OK;
+
+ /*
+ * we can use only one bdbuf :( and we also know that cache is useless
+ * for sync operation, so don't use it
+ */
+ rc = fat_buf_release(fs_info);
+ if (rc != RC_OK)
+ return rc;
+
+ /* for each cluster of the file ... */
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
+ /* for each sector in cluster ... */
+ for ( i = 0; i < fs_info->vol.spc; i++ )
+ {
+ /* ... sync it */
+ sc = rtems_bdbuf_read(fs_info->vol.dev, (sec + i), &block);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ sc = rtems_bdbuf_sync(block);
+ if ( sc != RTEMS_SUCCESSFUL )
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+ }
+ return rc;
+}
+
+/* fat_file_size --
+ * Calculate fat-file size - fat-file is nothing that clusters chain, so
+ * go through all clusters in the chain and count it. Only
+ * special case is root directory for FAT12/16 volumes.
+ * This function is used only for directories which are fat-files with
+ * non-zero length, hence 'fat_fd->cln' always contains valid data.
+ * Calculated size is stored in 'fat_file_size' field of fat-file
+ * descriptor.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+fat_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ int rc = RC_OK;
+ fat_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 cur_cln = fat_fd->cln;
+ unsigned32 save_cln = 0;
+
+ /* Have we requested root dir size for FAT12/16? */
+ if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
+ (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
+ {
+ fat_fd->fat_file_size = fs_info->vol.rdir_size;
+ return rc;
+ }
+
+ fat_fd->fat_file_size = 0;
+
+ while ((cur_cln & fs_info->vol.mask) != fs_info->vol.eoc_val)
+ {
+ save_cln = cur_cln;
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+
+ fat_fd->fat_file_size += fs_info->vol.bpc;
+ }
+ fat_fd->map.last_cln = save_cln;
+ return rc;
+}
+
+/* hash support routines */
+
+/* _hash_insert --
+ * Insert elemnt into hash based on key 'key1'
+ *
+ * PARAMETERS:
+ * hash - hash element will be inserted into
+ * key1 - key on which insertion is based on
+ * key2 - not used during insertion
+ * el - element to insert
+ *
+ * RETURNS:
+ * None
+ */
+static inline void
+_hash_insert(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el)
+{
+ _Chain_Append((hash) + ((key1) % FAT_HASH_MODULE), &(el)->link);
+}
+
+
+/* _hash_delete --
+ * Remove element from hash
+ *
+ * PARAMETERS:
+ * hash - hash element will be removed from
+ * key1 - not used
+ * key2 - not used
+ * el - element to delete
+ *
+ * RETURNS:
+ * None
+ */
+static inline void
+_hash_delete(Chain_Control *hash, unsigned32 key1, unsigned32 key2,
+ fat_file_fd_t *el)
+{
+ _Chain_Extract(&(el)->link);
+}
+
+/* _hash_search --
+ * Search element in hash. If both keys match pointer to found element
+ * is returned
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * hash - hash element will be removed from
+ * key1 - search key
+ * key2 - search key
+ * ret - placeholder for result
+ *
+ * RETURNS:
+ * 0 and pointer to found element on success, -1 otherwise
+ */
+static inline int
+_hash_search(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ Chain_Control *hash,
+ unsigned32 key1,
+ unsigned32 key2,
+ void **ret
+ )
+{
+ unsigned32 mod = (key1) % FAT_HASH_MODULE;
+ Chain_Node *the_node = ((Chain_Control *)((hash) + mod))->first;
+
+ for ( ; !_Chain_Is_tail((hash) + mod, the_node) ; )
+ {
+ fat_file_fd_t *ffd = (fat_file_fd_t *)the_node;
+ unsigned32 ck =
+ fat_construct_key(mt_entry, ffd->info_cln, ffd->info_ofs);
+
+ if ( (key1) == ck)
+ {
+ if ( ((key2) == 0) || ((key2) == ffd->ino) )
+ {
+ *ret = (void *)the_node;
+ return 0;
+ }
+ }
+ the_node = the_node->next;
+ }
+ return -1;
+}
+
+static int
+fat_file_lseek(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 file_cln,
+ unsigned32 *disk_cln
+ )
+{
+ int rc = RC_OK;
+/*
+ assert(fat_fd->fat_file_size);
+ */
+ if (file_cln == fat_fd->map.file_cln)
+ *disk_cln = fat_fd->map.disk_cln;
+ else
+ {
+ unsigned32 cur_cln;
+ unsigned32 count;
+ unsigned32 i;
+
+ if (file_cln > fat_fd->map.file_cln)
+ {
+ cur_cln = fat_fd->map.disk_cln;
+ count = file_cln - fat_fd->map.file_cln;
+ }
+ else
+ {
+ cur_cln = fat_fd->cln;
+ count = file_cln;
+ }
+
+ /* skip over the clusters */
+ for (i = 0; i < count; i++)
+ {
+ rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
+ if ( rc != RC_OK )
+ return rc;
+ }
+
+ /* update cache */
+ fat_fd->map.file_cln = file_cln;
+ fat_fd->map.disk_cln = cur_cln;
+
+ *disk_cln = cur_cln;
+ }
+ return RC_OK;
+}
diff --git a/cpukit/libfs/src/dosfs/fat_file.h b/cpukit/libfs/src/dosfs/fat_file.h
new file mode 100644
index 0000000000..2821a27cf7
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/fat_file.h
@@ -0,0 +1,195 @@
+/*
+ * fat_file.h
+ *
+ * Constants/data structures/prototypes for operations on "fat-file"
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_FAT_FILE_H__
+#define __DOSFS_FAT_FILE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <time.h>
+
+/* "fat-file" representation
+ *
+ * the idea is: fat-file is nothing but a cluster chain, any open fat-file is
+ * represented in system by fat-file descriptor and has well-known
+ * file interface:
+ *
+ * fat_file_open()
+ * fat_file_close()
+ * fat_file_read()
+ * fat_file_write()
+ *
+ * Such interface hides the architecture of fat-file and represents it like
+ * linear file
+ */
+
+typedef rtems_filesystem_node_types_t fat_file_type_t;
+
+#define FAT_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define FAT_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+typedef struct fat_file_map_s
+{
+ unsigned32 file_cln;
+ unsigned32 disk_cln;
+ unsigned32 last_cln;
+} fat_file_map_t;
+/*
+ * descriptor of a fat-file
+ *
+ * To each particular clusters chain
+ */
+typedef struct fat_file_fd_s
+{
+ Chain_Node link; /*
+ * fat-file descriptors organized into hash;
+ * collision lists are handled via link
+ * field
+ */
+ unsigned32 links_num; /*
+ * the number of fat_file_open call on
+ * this fat-file
+ */
+ unsigned32 ino; /* inode, file serial number :)))) */
+ fat_file_type_t fat_file_type;
+ unsigned32 size_limit;
+ unsigned32 fat_file_size; /* length */
+ unsigned32 info_cln;
+ unsigned32 cln;
+ unsigned16 info_ofs;
+ unsigned char first_char;
+ unsigned8 flags;
+ fat_file_map_t map;
+ time_t mtime;
+
+} fat_file_fd_t;
+
+
+#define FAT_FILE_REMOVED 0x01
+
+#define FAT_FILE_IS_REMOVED(p)\
+ (((p)->flags & FAT_FILE_REMOVED) ? 1 : 0)
+
+/* ioctl macros */
+#define F_CLU_NUM 0x01
+
+/*
+ * Each file and directory on a MSDOS volume is unique identified by it
+ * location, i.e. location of it 32 Bytes Directory Entry Structure. We can
+ * distinguish them by cluster number it locates on and offset inside this
+ * cluster. But root directory on any volumes (FAT12/16/32) has no 32 Bytes
+ * Directory Entry Structure corresponded to it. So we assume 32 Bytes
+ * Directory Entry Structure of root directory locates at cluster 1 (invalid
+ * cluaster number) and offset 0
+ */
+#define FAT_ROOTDIR_CLUSTER_NUM 0x01
+
+#define FAT_FD_OF_ROOT_DIR(fat_fd) \
+ ((fat_fd->info_cln == FAT_ROOTDIR_CLUSTER_NUM ) && \
+ (fat_fd->info_ofs == 0))
+
+#define FAT_EOF 0x00
+
+/* fat_construct_key --
+ * Construct key for hash access: convert (cluster num, offset) to
+ * (sector512 num, new offset) and than construct key as
+ * key = (sector512 num) << 4 | (new offset)
+ *
+ * PARAMETERS:
+ * cl - cluster number
+ * ofs - offset inside cluster 'cl'
+ * mt_entry - mount table entry
+ *
+ * RETURNS:
+ * constructed key
+ */
+static inline unsigned32
+fat_construct_key(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs)
+{
+ return ( ((fat_cluster_num_to_sector512_num(mt_entry, cl) +
+ (ofs >> FAT_SECTOR512_BITS)) << 4) +
+ ((ofs >> 5) & (FAT_DIRENTRIES_PER_SEC512 - 1)) );
+}
+
+/* Prototypes for "fat-file" operations */
+int
+fat_file_open(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ unsigned32 ofs,
+ fat_file_fd_t **fat_fd);
+
+int
+fat_file_reopen(fat_file_fd_t *fat_fd);
+
+int
+fat_file_close(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+ssize_t
+fat_file_read(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf);
+
+ssize_t
+fat_file_write(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 start,
+ unsigned32 count,
+ char *buf);
+
+int
+fat_file_extend(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length,
+ unsigned32 *a_length);
+
+int
+fat_file_truncate(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 new_length);
+
+int
+fat_file_datasync(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+
+int
+fat_file_ioctl(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ int cmd,
+ ...);
+
+int
+fat_file_size(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+void
+fat_file_mark_removed(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_FAT_FILE_H__ */
diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h
new file mode 100644
index 0000000000..a9216b1ed3
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos.h
@@ -0,0 +1,408 @@
+/*
+ * msdos.h
+ *
+ * The MSDOS filesystem constants/data structures/prototypes
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#ifndef __DOSFS_MSDOS_H__
+#define __DOSFS_MSDOS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_file.h"
+
+#ifndef RC_OK
+#define RC_OK 0x00000000
+#endif
+
+#define MSDOS_NAME_NOT_FOUND_ERR 0xDD000001
+
+/*
+ * This structure identifies the instance of the filesystem on the MSDOS
+ * level.
+ */
+typedef struct msdos_fs_info_s
+{
+ fat_fs_info_t fat; /*
+ * volume
+ * description
+ */
+ rtems_filesystem_file_handlers_r *directory_handlers; /*
+ * a set of routines
+ * that handles the
+ * nodes of directory
+ * type
+ */
+ rtems_filesystem_file_handlers_r *file_handlers; /*
+ * a set of routines
+ * that handles the
+ * nodes of file
+ * type
+ */
+ rtems_id vol_sema; /*
+ * semaphore
+ * associated with
+ * the volume
+ */
+ unsigned8 *cl_buf; /*
+ * just placeholder
+ * for anything
+ */
+} msdos_fs_info_t;
+
+/* a set of routines that handle the nodes which are directories */
+extern rtems_filesystem_file_handlers_r msdos_dir_handlers;
+
+/* a set of routines that handle the nodes which are files */
+extern rtems_filesystem_file_handlers_r msdos_file_handlers;
+
+/* Volume semaphore timeout value */
+#define MSDOS_VOLUME_SEMAPHORE_TIMEOUT 100
+
+/* Node types */
+#define MSDOS_DIRECTORY RTEMS_FILESYSTEM_DIRECTORY
+#define MSDOS_REGULAR_FILE RTEMS_FILESYSTEM_MEMORY_FILE
+
+typedef rtems_filesystem_node_types_t msdos_node_type_t;
+
+/*
+ * Macros for fetching fields from 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE 32 /* 32 bytes */
+
+#define MSDOS_DIR_NAME(x) (unsigned8 *)((x) + 0)
+#define MSDOS_DIR_ATTR(x) (unsigned8 *)((x) + 11)
+#define MSDOS_DIR_NT_RES(x) (unsigned8 *)((x) + 12)
+#define MSDOS_DIR_CRT_TIME_TENTH(x) (unsigned8 *)((x) + 13)
+#define MSDOS_DIR_CRT_TIME(x) (unsigned16 *)((x) + 14)
+#define MSDOS_DIR_CRT_DATE(x) (unsigned16 *)((x) + 16)
+#define MSDOS_DIR_LAST_ACCESS_DATE(x) (unsigned16 *)((x) + 18)
+#define MSDOS_DIR_FIRST_CLUSTER_HI(x) (unsigned16 *)((x) + 20)
+#define MSDOS_DIR_WRITE_TIME(x) (unsigned16 *)((x) + 22)
+#define MSDOS_DIR_WRITE_DATE(x) (unsigned16 *)((x) + 24)
+#define MSDOS_DIR_FIRST_CLUSTER_LOW(x) (unsigned16 *)((x) + 26)
+#define MSDOS_DIR_FILE_SIZE(x) (unsigned32 *)((x) + 28)
+
+#define MSDOS_EXTRACT_CLUSTER_NUM(p) \
+ (unsigned32)( (CF_LE_W(*MSDOS_DIR_FIRST_CLUSTER_LOW(p))) | \
+ ((CF_LE_W((*MSDOS_DIR_FIRST_CLUSTER_HI(p))))<<16) )
+
+/*
+ * Fields offset in 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_FILE_SIZE_OFFSET 28
+#define MSDOS_FILE_NAME_OFFSET 0
+#define MSDOS_FIRST_CLUSTER_HI_OFFSET 20
+#define MSDOS_FIRST_CLUSTER_LOW_OFFSET 26
+#define MSDOS_FILE_WDATE_OFFSET 24
+#define MSDOS_FILE_WTIME_OFFSET 22
+
+/*
+ * Possible values of DIR_Attr field of 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_ATTR_READ_ONLY 0x01
+#define MSDOS_ATTR_HIDDEN 0x02
+#define MSDOS_ATTR_SYSTEM 0x04
+#define MSDOS_ATTR_VOLUME_ID 0x08
+#define MSDOS_ATTR_DIRECTORY 0x10
+#define MSDOS_ATTR_ARCHIVE 0x20
+
+/*
+ * Possible values of DIR_Name[0] field of 32 bytes long FAT Directory Entry
+ * Structure (see M$ White Paper)
+ */
+#define MSDOS_THIS_DIR_ENTRY_EMPTY 0xE5
+#define MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY 0x00
+
+
+/*
+ * Macros for names parsing and formatting
+ */
+#define msdos_is_valid_name_char(_ch) (1)
+#define msdos_is_separator(_ch) rtems_filesystem_is_separator(_ch)
+
+#define MSDOS_SHORT_NAME_LEN 11 /* 11 characters */
+#define MSDOS_NAME_MAX MSDOS_SHORT_NAME_LEN
+#define MSDOS_NAME_MAX_WITH_DOT (MSDOS_NAME_MAX + 1)
+
+#define MSDOS_DOT_NAME ". " /* ".", padded to MSDOS_NAME chars */
+#define MSDOS_DOTDOT_NAME ".. " /* "..", padded to MSDOS_NAME chars */
+
+typedef enum msdos_token_types_e
+{
+ MSDOS_NO_MORE_PATH,
+ MSDOS_CURRENT_DIR,
+ MSDOS_UP_DIR,
+ MSDOS_NAME,
+ MSDOS_INVALID_TOKEN
+} msdos_token_types_t;
+
+/* Others macros */
+#define MSDOS_RES_NT_VALUE 0x00
+#define MSDOS_INIT_DIR_SIZE 0x00
+
+/* "dot" entry offset in a directory */
+#define MSDOS_DOT_DIR_ENTRY_OFFSET 0x00 /* first entry in directory */
+
+/* "dotdot" entry offset in a directory */
+#define MSDOS_DOTDOT_DIR_ENTRY_OFFSET 0x20 /* second entry in directory */
+
+/* 'p' should be char* */
+#define DOT_NODE_P(p) ((char *)(p))
+#define DOTDOT_NODE_P(p) ((char *)((p) + MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE))
+
+/* Size limits for files and directories (see M$ White Paper) */
+#define MSDOS_MAX_DIR_LENGHT 0x200000 /* 2,097,152 bytes */
+#define MSDOS_MAX_FILE_SIZE 0xFFFFFFFF /* 4 Gb */
+
+/*
+ * The number of 32 bytes long FAT Directory Entry
+ * Structures per 512 bytes sector
+ */
+#define MSDOS_DPS512_NUM 16
+
+/* Prototypes */
+int
+msdos_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+int
+msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry);
+
+int
+msdos_eval_path(const char *pathname, /* IN */
+ int flags, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */);
+
+int
+msdos_eval4make(const char *path, /* IN */
+ rtems_filesystem_location_info_t *pathloc, /* IN/OUT */
+ const char **name /* OUT */);
+
+int
+msdos_unlink(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_free_node_info(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+rtems_filesystem_node_types_t
+msdos_node_type(rtems_filesystem_location_info_t *pathloc);
+
+int
+msdos_mknod(const char *path, /* IN */
+ mode_t mode, /* IN */
+ dev_t dev, /* IN */
+ rtems_filesystem_location_info_t *pathloc /* IN/OUT */);
+
+int
+msdos_utime(rtems_filesystem_location_info_t *pathloc, /* IN */
+ time_t actime, /* IN */
+ time_t modtime /* IN */);
+
+int
+msdos_initialize_support(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry,
+ rtems_filesystem_operations_table *op_table,
+ rtems_filesystem_file_handlers_r *file_handlers,
+ rtems_filesystem_file_handlers_r *directory_handlers
+);
+
+int
+msdos_file_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+
+int
+msdos_file_close(rtems_libio_t *iop /* IN */);
+
+ssize_t
+msdos_file_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+ssize_t
+msdos_file_write(
+ rtems_libio_t *iop, /* IN */
+ const void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+int
+msdos_file_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+
+int
+msdos_file_stat(rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */);
+
+int
+msdos_file_ftruncate(
+ rtems_libio_t *iop, /* IN */
+ off_t length /* IN */
+);
+
+int
+msdos_file_sync(rtems_libio_t *iop);
+
+int
+msdos_file_datasync(rtems_libio_t *iop);
+
+int
+msdos_file_ioctl(
+ rtems_libio_t *iop, /* IN */
+ unsigned32 command, /* IN */
+ void *buffer /* IN */
+);
+
+int
+msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_dir_open(
+ rtems_libio_t *iop, /* IN */
+ const char *pathname, /* IN */
+ unsigned32 flag, /* IN */
+ unsigned32 mode /* IN */
+);
+
+int
+msdos_dir_close(rtems_libio_t *iop /* IN */);
+
+ssize_t
+msdos_dir_read(
+ rtems_libio_t *iop, /* IN */
+ void *buffer, /* IN */
+ unsigned32 count /* IN */
+);
+
+int
+msdos_dir_lseek(
+ rtems_libio_t *iop, /* IN */
+ off_t offset, /* IN */
+ int whence /* IN */
+);
+
+int
+msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc /* IN */);
+
+int
+msdos_dir_sync(rtems_libio_t *iop);
+
+int
+msdos_dir_stat(
+ rtems_filesystem_location_info_t *loc, /* IN */
+ struct stat *buf /* OUT */
+);
+
+int
+msdos_creat_node(rtems_filesystem_location_info_t *parent_loc,
+ msdos_node_type_t type,
+ char *name,
+ mode_t mode);
+
+/* Misc prototypes */
+msdos_token_types_t msdos_get_token(const char *path,
+ char *token,
+ int *token_len);
+
+int
+msdos_find_name(rtems_filesystem_location_info_t *parent_loc,
+ char *name);
+
+int
+msdos_get_name_node(rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry);
+
+int
+msdos_dir_info_remove(rtems_filesystem_location_info_t *pathloc);
+
+void
+msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date);
+
+unsigned int
+msdos_date_dos2unix(unsigned short time_val, unsigned short date);
+
+int
+msdos_set_first_cluster_num(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+int
+msdos_set_file_size(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd);
+
+int
+msdos_set_first_char4file_name(rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char first_char);
+
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+);
+
+
+int
+msdos_dir_is_empty(rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val);
+
+int
+msdos_find_name_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry);
+
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+);
+
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __DOSFS_MSDOS_H__ */
diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c
new file mode 100644
index 0000000000..4b4c7001ca
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_create.c
@@ -0,0 +1,208 @@
+/*
+ * Routine to create a new MSDOS filesystem node
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ *
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <rtems/libio_.h>
+#include <time.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_creat_node --
+ * Create a new node. If a new node is file, FAT 32 Bytes Directory
+ * Entry Structure (see M$ White Paper) is initialized, free space is
+ * found in parent directory and structure is written to the disk.
+ * In case of directory, all above steps present and also new cluster
+ * is allocated for a new directory and dot and dotdot nodes are created
+ * in alloceted cluster.
+ *
+ * PARAMETERS:
+ * parent_loc - parent (directory we are going to create node in)
+ * type - new node type (file or directory)
+ * name - new node name
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ *
+ */
+int
+msdos_creat_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ msdos_node_type_t type,
+ char *name,
+ mode_t mode
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *parent_fat_fd = parent_loc->node_access;
+ fat_file_fd_t *fat_fd = NULL;
+ time_t time_ret = 0;
+ unsigned16 time_val = 0;
+ unsigned16 date = 0;
+ fat_auxiliary_t aux;
+ unsigned char new_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
+
+ memset(new_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);
+
+ /* set up name */
+ strncpy(MSDOS_DIR_NAME(new_node), name, MSDOS_NAME_MAX);
+
+ /* fill reserved field */
+ *MSDOS_DIR_NT_RES(new_node) = MSDOS_RES_NT_VALUE;
+
+ /* set up last write date and time */
+ time_ret = time(NULL);
+ if ( time_ret == -1 )
+ return -1;
+
+ msdos_date_unix2dos(time_ret, &time_val, &date);
+ *MSDOS_DIR_WRITE_TIME(new_node) = CT_LE_W(time_val);
+ *MSDOS_DIR_WRITE_DATE(new_node) = CT_LE_W(date);
+
+ /* initialize directory/file size */
+ *MSDOS_DIR_FILE_SIZE(new_node) = MSDOS_INIT_DIR_SIZE;
+
+ if (type == MSDOS_DIRECTORY)
+ *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_DIRECTORY;
+ else
+ *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE;
+
+ /*
+ * find free space in the parent directory and write new initialized
+ * FAT 32 Bytes Directory Entry Structure (see M$ White Paper)
+ * to the disk
+ */
+ rc = msdos_get_name_node(parent_loc, NULL, &aux, new_node);
+ if ( rc != RC_OK )
+ return rc;
+
+ /*
+ * if we create a new file we are done, if directory there are more steps
+ * to do
+ */
+ if (type == MSDOS_DIRECTORY)
+ {
+ /* open new directory as fat-file */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ /*
+ * we opened fat-file for node we just created, so initialize fat-file
+ * descritor
+ */
+ fat_fd->info_cln = aux.cln;
+ fat_fd->info_ofs = aux.ofs;
+ fat_fd->fat_file_size = 0;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ /*
+ * dot and dotdot entries are identical to new node except the
+ * names
+ */
+ memcpy(DOT_NODE_P(dot_dotdot), new_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memcpy(DOTDOT_NODE_P(dot_dotdot), new_node,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME,
+ MSDOS_NAME_MAX);
+ memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME,
+ MSDOS_NAME_MAX);
+
+ /* set up cluster num for dotdot entry */
+ /*
+ * here we can ommit FAT32 condition because for all FAT types dirs
+ * right under root dir should contain 0 in dotdot entry but for
+ * FAT12/16 parent_fat_fd->cluster_num always contains such value
+ */
+ if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) &&
+ (fs_info->fat.vol.type & FAT_FAT32))
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000;
+ }
+ else
+ {
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)((parent_fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)(((parent_fat_fd->cln) & 0xFFFF0000)>>16));
+ }
+
+ /*
+ * write dot and dotdot entries to new fat-file: currently fat-file
+ * correspondes to a new node is zero length, so it will be extended
+ * by one cluster and entries will be written
+ */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2,
+ dot_dotdot);
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* increment fat-file size by cluster size */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* set up cluster num for dot entry */
+ *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)((fat_fd->cln) & 0x0000FFFF));
+ *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) =
+ CT_LE_W((unsigned16)(((fat_fd->cln) & 0xFFFF0000) >> 16));
+
+ /* rewrite dot entry */
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ DOT_NODE_P(dot_dotdot));
+ if (ret < 0)
+ {
+ rc = -1;
+ goto error;
+ }
+
+ /* write first cluster num of a new directory to disk */
+ rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto error;
+
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ }
+ return RC_OK;
+
+error:
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+
+err:
+ /* mark 32bytes structure on the disk as free */
+ msdos_set_first_char4file_name(parent_loc->mt_entry, aux.cln, aux.ofs,
+ 0xE5);
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c
new file mode 100644
index 0000000000..93449cd2fb
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_dir.c
@@ -0,0 +1,483 @@
+/*
+ * MSDOS directory handlers implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <rtems/libio_.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_dir_open --
+ * Open fat-file which correspondes to the directory being opened and
+ * set offset field of file control block to zero.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * pathname - name
+ * flag - flags
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK, if directory opened successfully, or -1 if error occured (errno
+ * set apropriately)
+ */
+int
+msdos_dir_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
+ unsigned32 mode)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ iop->offset = 0;
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_close --
+ * Close fat-file which correspondes to the directory being closed
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK, if directory closed successfully, or -1 if error occured (errno
+ * set apropriately.
+ */
+int
+msdos_dir_close(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one( EIO );
+
+ rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_read --
+ * 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.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - buffer provided by user
+ * count - count of bytes to read
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+ssize_t
+msdos_dir_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ fat_file_fd_t *tmp_fat_fd = NULL;
+ struct dirent tmp_dirent;
+ unsigned32 start = 0;
+ ssize_t ret = 0;
+ unsigned32 cmpltd = 0;
+ unsigned32 j = 0, i = 0;
+ unsigned32 bts2rd = 0;
+ unsigned32 cur_cln = 0;
+
+ /*
+ * cast start and count - protect against using sizes that are not exact
+ * multiples of the -dirent- size. These could result in unexpected
+ * results
+ */
+ start = iop->offset / sizeof(struct dirent);
+ count = (count / sizeof(struct dirent)) * sizeof(struct dirent);
+
+ /*
+ * optimization: we know that root directory for FAT12/16 volumes is
+ * sequential set of sectors and any cluster is sequential set of sectors
+ * too, so read such set of sectors is quick operation for low-level IO
+ * layer.
+ */
+ bts2rd = (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16))) ?
+ fat_fd->fat_file_size :
+ fs_info->fat.vol.bpc;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ while (count > 0)
+ {
+ /*
+ * fat-file is already opened by open call, so read it
+ * Always read directory fat-file from the beggining because of MSDOS
+ * directories feature :( - we should count elements currently
+ * present in the directory because there may be holes :)
+ */
+ ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, (j * bts2rd),
+ bts2rd, fs_info->cl_buf);
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EIO);
+ }
+
+ for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return cmpltd;
+ }
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY)
+ continue;
+
+ /*
+ * skip active entries until get the entry to start from
+ */
+ if (start)
+ {
+ start--;
+ continue;
+ }
+
+ /*
+ * Move the entry to the return buffer
+ *
+ * unfortunately there is no method to extract ino except to
+ * open fat-file descriptor :( ... so, open it
+ */
+
+ /* get number of cluster we are working with */
+ rc = fat_file_ioctl(iop->pathinfo.mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &cur_cln);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = fat_file_open(iop->pathinfo.mt_entry, cur_cln, i,
+ &tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ tmp_fat_fd->info_cln = cur_cln;
+ tmp_fat_fd->info_ofs = i;
+
+ /* fill in dirent structure */
+ /* XXX: from what and in what d_off should be computed ?! */
+ tmp_dirent.d_off = start + cmpltd;
+ tmp_dirent.d_reclen = sizeof(struct dirent);
+ tmp_dirent.d_ino = tmp_fat_fd->ino;
+ tmp_dirent.d_namlen = MSDOS_SHORT_NAME_LEN;
+ memcpy(tmp_dirent.d_name, MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_SHORT_NAME_LEN);
+
+ /* d_name is null-terminated */
+ tmp_dirent.d_name[MSDOS_SHORT_NAME_LEN] = 0;
+ memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
+
+ iop->offset = iop->offset + sizeof(struct dirent);
+ cmpltd += (sizeof(struct dirent));
+ count -= (sizeof(struct dirent));
+
+ /* inode number extracted, close fat-file */
+ rc = fat_file_close(iop->pathinfo.mt_entry, tmp_fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (count <= 0)
+ break;
+ }
+ j++;
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return cmpltd;
+}
+
+/* msdos_dir_write --
+ * no write for directory
+ */
+
+/* msdos_dir_lseek --
+ *
+ * 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.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * offset - offset
+ * whence - predefine directive
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+int
+msdos_dir_lseek(rtems_libio_t *iop, off_t offset, int whence)
+{
+ switch (whence)
+ {
+ case SEEK_SET:
+ case SEEK_CUR:
+ break;
+ /*
+ * Movement past the end of the directory via lseek is not a
+ * permitted operation
+ */
+ case SEEK_END:
+ default:
+ set_errno_and_return_minus_one( EINVAL );
+ break;
+ }
+ return RC_OK;
+}
+
+/* msdos_dir_stat --
+ *
+ * This routine will obtain the following information concerning the current
+ * directory:
+ * st_dev device id
+ * st_ino node serial number :)
+ * st_mode mode extracted from the node
+ * st_size total size in bytes
+ * st_blksize blocksize for filesystem I/O
+ * st_blocks number of blocks allocated
+ * stat_mtime time of last modification
+ *
+ * PARAMETERS:
+ * loc - this directory
+ * buf - stat buffer provided by user
+ *
+ * RETURNS:
+ * RC_OK and filled stat buffer on success, or -1 if error occured (errno
+ * set apropriately).
+ */
+int
+msdos_dir_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+ )
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ buf->st_dev = fs_info->fat.vol.dev;
+ buf->st_ino = fat_fd->ino;
+ buf->st_mode = S_IFDIR;
+ buf->st_rdev = 0ll;
+ buf->st_size = fat_fd->fat_file_size;
+ buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
+ buf->st_blksize = fs_info->fat.vol.bps;
+ buf->st_mtime = fat_fd->mtime;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_dir_truncate --
+ * No truncate for directory.
+ *
+ * PARAMETERS:
+ *
+ * RETURNS:
+ *
+ */
+
+/* msdos_dir_sync --
+ * The following routine does a syncronization on a MSDOS directory node.
+ * DIR_WrtTime, DIR_WrtDate and DIR_fileSize fields of 32 Bytes Directory
+ * Entry Structure(see M$ White Paper) should not be updated for
+ * directories, so only call to corresponding fat-file routine.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ */
+int
+msdos_dir_sync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_dir_rmnod --
+ * Remove directory node.
+ *
+ * Check that this directory node is not opened as fat-file, is empty and
+ * not filesystem root node. If all this conditions met then delete.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ */
+int
+msdos_dir_rmnod(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = pathloc->node_access;
+ rtems_boolean is_empty = FALSE;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /*
+ * We deny attemp to delete open directory (if directory is current
+ * directory we assume it is open one)
+ */
+ if (fat_fd->links_num > 1)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EBUSY);
+ }
+
+ /*
+ * You cannot remove a node that still has children
+ */
+ rc = msdos_dir_is_empty(pathloc->mt_entry, fat_fd, &is_empty);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (!is_empty)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(ENOTEMPTY);
+ }
+
+ /*
+ * You cannot remove the file system root node.
+ */
+ if (pathloc->mt_entry->mt_fs_root.node_access == pathloc->node_access)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ set_errno_and_return_minus_one(EBUSY);
+ }
+
+ /*
+ * You cannot remove a mountpoint.
+ * not used - mount() not implemenetd yet.
+ */
+
+ /* mark file removed */
+ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
+ fat_fd->info_ofs,
+ MSDOS_THIS_DIR_ENTRY_EMPTY);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ fat_file_mark_removed(pathloc->mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_eval.c b/cpukit/libfs/src/dosfs/msdos_eval.c
new file mode 100644
index 0000000000..3eba0e63e8
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_eval.c
@@ -0,0 +1,435 @@
+/*
+ * MSDOS evaluation routines
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_set_handlers --
+ * Set handlers for the node with specified type(i.e. handlers for file
+ * or directory).
+ *
+ * PARAMETERS:
+ * loc - node description
+ *
+ * RETURNS:
+ * None
+ */
+static void
+msdos_set_handlers(rtems_filesystem_location_info_t *loc)
+{
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ if (fat_fd->fat_file_type == FAT_DIRECTORY)
+ loc->handlers = fs_info->directory_handlers;
+ else
+ loc->handlers = fs_info->file_handlers;
+}
+
+/* msdos_eval_path --
+ *
+ * The following routine evaluate path for a node that wishes to be
+ * accessed. Structure 'pathloc' is returned with a pointer to the
+ * node to be accessed.
+ *
+ * PARAMETERS:
+ * pathname - path for evaluation
+ * flags - flags
+ * pathloc - node description (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK and filled pathloc on success, or -1 if error occured
+ * (errno set appropriately)
+ *
+ */
+int
+msdos_eval_path(
+ const char *pathname,
+ int flags,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ int i = 0;
+ int len = 0;
+ msdos_token_types_t type = MSDOS_CURRENT_DIR;
+ char token[MSDOS_NAME_MAX + 1];
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while ((type != MSDOS_NO_MORE_PATH) && (type != MSDOS_INVALID_TOKEN))
+ {
+ type = msdos_get_token(&pathname[i], token, &len);
+ i += len;
+
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalpath_h)(&(pathname[i-len]),
+ flags, pathloc);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ /*
+ * Always return the root node.
+ *
+ * If we are at a node that is a mount point. Set loc to the
+ * new fs root node and let let the mounted filesystem set the handlers.
+ *
+ * NOTE: The behavior of stat() on a mount point appears to be
+ * questionable.
+ * NOTE: MSDOS filesystem currently doesn't support mount functionality ->
+ * action not implemented
+ */
+ fat_fd = pathloc->node_access;
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_eval4make --
+ * The following routine evaluate path for a new node to be created.
+ * 'pathloc' is returned with a pointer to the parent of the new node.
+ * 'name' is returned with a pointer to the first character in the
+ * new node name. The parent node is verified to be a directory.
+ *
+ * PARAMETERS:
+ * path - path for evaluation
+ * pathloc - IN/OUT (start point for evaluation/parent directory for
+ * creation)
+ * name - new node name
+ *
+ * RETURNS:
+ * RC_OK, filled pathloc for parent directory and name of new node on
+ * success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_eval4make(
+ const char *path,
+ rtems_filesystem_location_info_t *pathloc,
+ const char **name
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ rtems_filesystem_location_info_t newloc;
+ msdos_token_types_t type;
+ int i = 0;
+ int len;
+ char token[ MSDOS_NAME_MAX + 1 ];
+ rtems_boolean done = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ if (!pathloc->node_access)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto err;
+ }
+
+ fat_fd = pathloc->node_access;
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ while (!done)
+ {
+ type = msdos_get_token(&path[i], token, &len);
+ i += len;
+ fat_fd = pathloc->node_access;
+
+ switch (type)
+ {
+ case MSDOS_UP_DIR:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Am I at the root of this mounted filesystem?
+ */
+ if (pathloc->node_access ==
+ pathloc->mt_entry->mt_fs_root.node_access)
+ {
+ /*
+ * Am I at the root of all filesystems?
+ * XXX: MSDOS is not supposed to be base fs.
+ */
+ if (pathloc->node_access ==
+ rtems_filesystem_root.node_access)
+ {
+ break; /* Throw out the .. in this case */
+ }
+ else
+ {
+ newloc = pathloc->mt_entry->mt_point_node;
+ *pathloc = newloc;
+
+ rc = fat_file_close(pathloc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ goto err;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return (*pathloc->ops->evalformake_h)(&path[i-len],
+ pathloc, name);
+ }
+ }
+ else
+ {
+ rc = msdos_find_name(pathloc, token);
+ if (rc != RC_OK)
+ {
+ if (rc == MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ }
+ goto error;
+ }
+ }
+ break;
+
+ case MSDOS_NAME:
+ /*
+ * Only a directory can be decended into.
+ */
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ /*
+ * Otherwise find the token name in the present location and
+ * set the node access to the point we have found.
+ */
+ rc = msdos_find_name(pathloc, token);
+ if (rc)
+ {
+ if (rc != MSDOS_NAME_NOT_FOUND_ERR)
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ else
+ done = TRUE;
+ }
+ break;
+
+ case MSDOS_NO_MORE_PATH:
+ errno = EEXIST;
+ rc = -1;
+ goto error;
+ break;
+
+ case MSDOS_CURRENT_DIR:
+ break;
+
+ case MSDOS_INVALID_TOKEN:
+ errno = ENAMETOOLONG;
+ rc = -1;
+ goto error;
+ break;
+
+ }
+ }
+
+ *name = &path[i - len];
+
+ /*
+ * We have evaluated the path as far as we can.
+ * Verify there is not any invalid stuff at the end of the name.
+ */
+ for( ; path[i] != '\0'; i++)
+ {
+ if (!msdos_is_separator(path[i]))
+ {
+ errno = ENOENT;
+ rc = -1;
+ goto error;
+ }
+ }
+
+ fat_fd = pathloc->node_access;
+
+ if (fat_fd->fat_file_type != FAT_DIRECTORY)
+ {
+ errno = ENOTDIR;
+ rc = -1;
+ goto error;
+ }
+
+ msdos_set_handlers(pathloc);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+
+error:
+ fat_file_close(pathloc->mt_entry, fat_fd);
+
+err:
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_file.c b/cpukit/libfs/src/dosfs/msdos_file.c
new file mode 100644
index 0000000000..da36827338
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_file.c
@@ -0,0 +1,485 @@
+/*
+ * MSDOS file handlers implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <rtems.h>
+#include <rtems/libio.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_file_open --
+ * Open fat-file which correspondes to the file
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * pathname - name
+ * flag - flags
+ * mode - mode
+ *
+ * RETURNS:
+ * RC_OK, if file opened successfully, or -1 if error occured
+ * and errno set appropriately
+ */
+int
+msdos_file_open(rtems_libio_t *iop, const char *pathname, unsigned32 flag,
+ unsigned32 mode)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_reopen(fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (iop->flags & LIBIO_FLAGS_APPEND)
+ iop->offset = fat_fd->fat_file_size;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_close --
+ * Close fat-file which correspondes to the file. If fat-file descriptor
+ * which correspondes to the file is not marked "removed", synchronize
+ * size, first cluster number, write time and date fields of the file.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK, if file closed successfully, or -1 if error occured (errno set
+ * appropriately)
+ */
+int
+msdos_file_close(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /*
+ * if fat-file descriptor is not marked as "removed", synchronize
+ * size, first cluster number, write time and date fields of the file
+ */
+ if (!FAT_FILE_IS_REMOVED(fat_fd))
+ {
+ rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ }
+
+ rc = fat_file_close(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
+
+/* msdos_file_read --
+ * This routine read from file pointed to by file control block into
+ * the specified data buffer provided by user
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - buffer provided by user
+ * count - the number of bytes to read
+ *
+ * RETURNS:
+ * the number of bytes read on success, or -1 if error occured (errno set
+ * appropriately)
+ */
+ssize_t
+msdos_file_read(rtems_libio_t *iop, void *buffer, unsigned32 count)
+{
+ ssize_t ret = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ ret = fat_file_read(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
+ buffer);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return ret;
+}
+
+/* msdos_file_write --
+ * This routine writes the specified data buffer into the file pointed to
+ * by file control block.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * buffer - data to write
+ * count - count of bytes to write
+ *
+ * RETURNS:
+ * the number of bytes written on success, or -1 if error occured
+ * and errno set appropriately
+ */
+ssize_t
+msdos_file_write(rtems_libio_t *iop,const void *buffer, unsigned32 count)
+{
+ ssize_t ret = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ ret = fat_file_write(iop->pathinfo.mt_entry, fat_fd, iop->offset, count,
+ buffer);
+ if (ret < 0)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return -1;
+ }
+
+ /*
+ * update file size in both fat-file descriptor and file control block if
+ * file was extended
+ */
+ if (iop->offset + ret > fat_fd->fat_file_size)
+ fat_fd->fat_file_size = iop->offset + ret;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return ret;
+}
+
+/* msdos_file_lseek --
+ * Process lseek call to the file: extend file if lseek is up to the end
+ * of the file.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * offset - new offset
+ * whence - predefine directive
+ *
+ * RETURNS:
+ * new offset on success, or -1 if error occured (errno set
+ * appropriately).
+ */
+int
+msdos_file_lseek(rtems_libio_t *iop, off_t offset, int whence)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ unsigned32 real_size = 0;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_extend(iop->pathinfo.mt_entry, fat_fd, iop->offset,
+ &real_size);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ if (real_size > fat_fd->fat_file_size)
+ fat_fd->fat_file_size = iop->offset = real_size;
+
+ iop->size = fat_fd->fat_file_size;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return iop->offset;
+}
+
+/* msdos_file_stat --
+ *
+ * PARAMETERS:
+ * loc - node description
+ * buf - stat buffer provided by user
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_stat(
+ rtems_filesystem_location_info_t *loc,
+ struct stat *buf
+ )
+{
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = loc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ buf->st_dev = fs_info->fat.vol.dev;
+ buf->st_ino = fat_fd->ino;
+ buf->st_mode = S_IFREG;
+ buf->st_rdev = 0ll;
+ buf->st_size = fat_fd->fat_file_size;
+ buf->st_blocks = fat_fd->fat_file_size >> FAT_SECTOR512_BITS;
+ buf->st_blksize = fs_info->fat.vol.bps;
+ buf->st_mtime = fat_fd->mtime;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_ftruncate --
+ * Truncate the file (if new length is greater then current do nothing).
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * length - new length
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately).
+ */
+int
+msdos_file_ftruncate(rtems_libio_t *iop, off_t length)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = iop->file_info;
+
+ if (length >= fat_fd->fat_file_size)
+ return RC_OK;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_truncate(iop->pathinfo.mt_entry, fat_fd, length);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ /*
+ * fat_file_truncate do nothing if new length >= fat-file size, so update
+ * file size only if length < fat-file size
+ */
+ if (length < fat_fd->fat_file_size)
+ iop->size = fat_fd->fat_file_size = length;
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_sync --
+ * Synchronize file - synchronize file data and if file is not removed
+ * synchronize file metadata.
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_sync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* synchronize file data */
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ /*
+ * if fat-file descriptor is not marked "removed" - synchronize file
+ * metadata
+ */
+ if (!FAT_FILE_IS_REMOVED(fat_fd))
+ {
+ rc = msdos_set_first_cluster_num(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ rc = msdos_set_file_size(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ rc = msdos_set_dir_wrt_time_and_date(iop->pathinfo.mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+ }
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+/* msdos_file_datasync --
+ * Synchronize file - synchronize only file data (metadata is letf intact).
+ *
+ * PARAMETERS:
+ * iop - file control block
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_datasync(rtems_libio_t *iop)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ fat_file_fd_t *fat_fd = iop->file_info;
+ msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* synchronize file data */
+ rc = fat_file_datasync(iop->pathinfo.mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
+
+
+/* msdos_file_ioctl --
+ *
+ *
+ * PARAMETERS:
+ * iop - file control block
+ * ...
+ *
+ * RETURNS:
+ *
+ */
+int
+msdos_file_ioctl(rtems_libio_t *iop,unsigned32 command, void *buffer)
+{
+ int rc = RC_OK;
+
+ return rc;
+}
+
+/* msdos_file_rmnod --
+ * Remove node associated with a file - set up first name character to
+ * predefined value(and write it to the disk), and mark fat-file which
+ * correspondes to the file as "removed"
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set appropriately)
+ */
+int
+msdos_file_rmnod(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = pathloc->node_access;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* mark file removed */
+ rc = msdos_set_first_char4file_name(pathloc->mt_entry, fat_fd->info_cln,
+ fat_fd->info_ofs,
+ MSDOS_THIS_DIR_ENTRY_EMPTY);
+ if (rc != RC_OK)
+ {
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+ }
+
+ fat_file_mark_removed(pathloc->mt_entry, fat_fd);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return RC_OK;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_free.c b/cpukit/libfs/src/dosfs/msdos_free.c
new file mode 100644
index 0000000000..c0d5938dbb
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_free.c
@@ -0,0 +1,56 @@
+/*
+ * Free node handler implementation for the filesystem
+ * operations table.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include <errno.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_free_node_info --
+ * Call fat-file close routine.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 code if error occured
+ *
+ */
+int
+msdos_free_node_info(rtems_filesystem_location_info_t *pathloc)
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ rc = fat_file_close(pathloc->mt_entry, pathloc->node_access);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_fsunmount.c b/cpukit/libfs/src/dosfs/msdos_fsunmount.c
new file mode 100644
index 0000000000..9072a2fad5
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_fsunmount.c
@@ -0,0 +1,71 @@
+/*
+ * MSDOS shut down handler implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_shut_down --
+ * Shut down MSDOS filesystem - free all allocated resources (don't
+ * return if deallocation of some resource failed - free as much as
+ * possible).
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = temp_mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = temp_mt_entry->mt_fs_root.node_access;
+
+ /* close fat-file which correspondes to root directory */
+ if (fat_file_close(temp_mt_entry, fat_fd) != RC_OK)
+ {
+ /* no return - try to free as much as possible */
+ rc = -1;
+ }
+
+ if (fat_shutdown_drive(temp_mt_entry) != RC_OK)
+ {
+ /* no return - try to free as much as possible */
+ rc = -1;
+ }
+
+ rtems_semaphore_delete(fs_info->vol_sema);
+ free(fs_info->cl_buf);
+ free(temp_mt_entry->fs_info);
+
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_handlers_dir.c b/cpukit/libfs/src/dosfs/msdos_handlers_dir.c
new file mode 100644
index 0000000000..e14d892add
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_handlers_dir.c
@@ -0,0 +1,36 @@
+/*
+ * Directory Handlers Table for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio.h>
+#include "msdos.h"
+
+rtems_filesystem_file_handlers_r msdos_dir_handlers = {
+ msdos_dir_open,
+ msdos_dir_close,
+ msdos_dir_read,
+ NULL, /* msdos_dir_write */
+ NULL, /* msdos_dir_ioctl */
+ msdos_dir_lseek,
+ msdos_dir_stat,
+ NULL,
+ NULL, /* msdos_dir_ftruncate */
+ NULL,
+ msdos_dir_sync,
+ msdos_dir_sync,
+ NULL, /* msdos_dir_fcntl */
+ msdos_dir_rmnod
+};
diff --git a/cpukit/libfs/src/dosfs/msdos_handlers_file.c b/cpukit/libfs/src/dosfs/msdos_handlers_file.c
new file mode 100644
index 0000000000..ae627066de
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_handlers_file.c
@@ -0,0 +1,36 @@
+/*
+ * File Operations Table for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio.h>
+#include "msdos.h"
+
+rtems_filesystem_file_handlers_r msdos_file_handlers = {
+ msdos_file_open,
+ msdos_file_close,
+ msdos_file_read,
+ msdos_file_write,
+ msdos_file_ioctl,
+ msdos_file_lseek,
+ msdos_file_stat,
+ NULL,
+ msdos_file_ftruncate,
+ NULL,
+ msdos_file_sync,
+ msdos_file_datasync,
+ NULL, /* msdos_file_fcntl */
+ msdos_file_rmnod
+};
diff --git a/cpukit/libfs/src/dosfs/msdos_init.c b/cpukit/libfs/src/dosfs/msdos_init.c
new file mode 100644
index 0000000000..2d5bf6c9e0
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_init.c
@@ -0,0 +1,60 @@
+/*
+ * Init routine for MSDOS
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <rtems/libio_.h>
+#include "msdos.h"
+
+rtems_filesystem_operations_table msdos_ops = {
+ msdos_eval_path,
+ msdos_eval4make,
+ NULL, /* msdos_link */
+ msdos_file_rmnod,
+ msdos_node_type,
+ msdos_mknod,
+ NULL, /* msdos_chown */
+ msdos_free_node_info,
+ NULL,
+ msdos_initialize,
+ NULL,
+ msdos_shut_down, /* msdos_shut_down */
+ NULL, /* msdos_utime */
+ NULL,
+ NULL,
+ NULL
+};
+
+/* msdos_initialize --
+ * MSDOS filesystem initialization
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_initialize(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
+{
+ int rc = RC_OK;
+
+ rc = msdos_initialize_support(temp_mt_entry,
+ &msdos_ops,
+ &msdos_file_handlers,
+ &msdos_dir_handlers);
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_initsupp.c b/cpukit/libfs/src/dosfs/msdos_initsupp.c
new file mode 100644
index 0000000000..eee8a6f9b2
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_initsupp.c
@@ -0,0 +1,149 @@
+/*
+ * MSDOS Initialization support routine implementation
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <assert.h>
+#include <rtems.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_initialize_support --
+ * MSDOS filesystem initialization
+ *
+ * PARAMETERS:
+ * temp_mt_entry - mount table entry
+ * op_table - filesystem operations table
+ * file_handlers - file operations table
+ * directory_handlers - directory operations table
+ *
+ * RETURNS:
+ * RC_OK and filled temp_mt_entry on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_initialize_support(
+ rtems_filesystem_mount_table_entry_t *temp_mt_entry,
+ rtems_filesystem_operations_table *op_table,
+ rtems_filesystem_file_handlers_r *file_handlers,
+ rtems_filesystem_file_handlers_r *directory_handlers
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = NULL;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned32 cl_buf_size;
+
+ fs_info = (msdos_fs_info_t *)calloc(1, sizeof(msdos_fs_info_t));
+ if (!fs_info)
+ set_errno_and_return_minus_one(ENOMEM);
+
+ temp_mt_entry->fs_info = fs_info;
+
+ rc = fat_init_volume_info(temp_mt_entry);
+ if (rc != RC_OK)
+ {
+ free(fs_info);
+ return rc;
+ }
+
+ fs_info->file_handlers = file_handlers;
+ fs_info->directory_handlers = directory_handlers;
+
+ /*
+ * open fat-file which correspondes to root directory
+ * (so inode number 0x00000010 is always used for root directory)
+ */
+ rc = fat_file_open(temp_mt_entry, FAT_ROOTDIR_CLUSTER_NUM, 0, &fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ return rc;
+ }
+
+ /* again: unfortunately "fat-file" is just almost fat file :( */
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+ fat_fd->info_cln = FAT_ROOTDIR_CLUSTER_NUM;
+ fat_fd->info_ofs = 0;
+ fat_fd->cln = fs_info->fat.vol.rdir_cl;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ /* if we have FAT12/16 */
+ if ( fat_fd->cln == 0 )
+ {
+ fat_fd->fat_file_size = fs_info->fat.vol.rdir_size;
+ cl_buf_size = (fs_info->fat.vol.bpc > fs_info->fat.vol.rdir_size) ?
+ fs_info->fat.vol.bpc :
+ fs_info->fat.vol.rdir_size;
+ }
+ else
+ {
+ rc = fat_file_size(temp_mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ return rc;
+ }
+ cl_buf_size = fs_info->fat.vol.bpc;
+ }
+
+ fs_info->cl_buf = (char *)calloc(cl_buf_size, sizeof(char));
+ if (fs_info->cl_buf == NULL)
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info);
+ set_errno_and_return_minus_one(ENOMEM);
+ }
+
+ sc = rtems_semaphore_create(3,
+ 1,
+ RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO,
+ RTEMS_INHERIT_PRIORITY,
+ &fs_info->vol_sema);
+ if (sc != RTEMS_SUCCESSFUL)
+ {
+ fat_file_close(temp_mt_entry, fat_fd);
+ fat_shutdown_drive(temp_mt_entry);
+ free(fs_info->cl_buf);
+ free(fs_info);
+ set_errno_and_return_minus_one( EIO );
+ }
+
+ temp_mt_entry->mt_fs_root.node_access = fat_fd;
+ temp_mt_entry->mt_fs_root.handlers = directory_handlers;
+ temp_mt_entry->mt_fs_root.ops = op_table;
+
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c
new file mode 100644
index 0000000000..fe2779f7a8
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_misc.c
@@ -0,0 +1,1087 @@
+/*
+ * Miscellaneous routines implementation for MSDOS filesystem
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* This copied from Linux */
+static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
+ /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
+
+#undef CONFIG_ATARI
+
+/* MS-DOS "device special files" */
+static const char *reserved_names[] = {
+#ifndef CONFIG_ATARI /* GEMDOS is less stupid */
+ "CON ","PRN ","NUL ","AUX ",
+ "LPT1 ","LPT2 ","LPT3 ","LPT4 ",
+ "COM1 ","COM2 ","COM3 ","COM4 ",
+#endif
+ NULL };
+
+static char bad_chars[] = "*?<>|\"";
+#ifdef CONFIG_ATARI
+/* GEMDOS is less restrictive */
+static char bad_if_strict[] = " ";
+#else
+static char bad_if_strict[] = "+=,; ";
+#endif
+
+/* The following three functions copied from Linux */
+/*
+ * Formats an MS-DOS file name. Rejects invalid names
+ *
+ * conv is relaxed/normal/strict, name is proposed name,
+ * len is the length of the proposed name, res is the result name,
+ * dotsOK is if hidden files get dots.
+ */
+int
+msdos_format_name(char conv, const char *name, int len, char *res,
+ char dotsOK)
+{
+ char *walk;
+ const char **reserved;
+ unsigned char c;
+ int space;
+ if (name[0] == '.') { /* dotfile because . and .. already done */
+ if (!dotsOK) return -EINVAL;
+ /* Get rid of dot - test for it elsewhere */
+ name++; len--;
+ }
+#ifndef CONFIG_ATARI
+ space = 1; /* disallow names that _really_ start with a dot */
+#else
+ space = 0; /* GEMDOS does not care */
+#endif
+ c = 0;
+ for (walk = res; len && walk-res < 8; walk++) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL;
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
+/* 0xE5 is legal as a first character, but we must substitute 0x05 */
+/* because 0xE5 marks deleted files. Yes, DOS really does this. */
+/* It seems that Microsoft hacked DOS to support non-US characters */
+/* after the 0xE5 character was already in use to mark deleted files. */
+ if((res==walk) && (c==0xE5)) c=0x05;
+ if (c == '.') break;
+ space = (c == ' ');
+ *walk = (c >= 'a' && c <= 'z') ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len && c != '.') {
+ c = *name++;
+ len--;
+ if (c != '.') return -EINVAL;
+ }
+ while (c != '.' && len--) c = *name++;
+ if (c == '.') {
+ while (walk-res < 8) *walk++ = ' ';
+ while (len > 0 && walk-res < MSDOS_NAME_MAX) {
+ c = *name++;
+ len--;
+ if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL;
+ if (conv == 's' && strchr(bad_if_strict,c))
+ return -EINVAL;
+ if (c < ' ' || c == ':' || c == '\\')
+ return -EINVAL;
+ if (c == '.') {
+ if (conv == 's')
+ return -EINVAL;
+ break;
+ }
+ if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL;
+ space = c == ' ';
+ *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
+ }
+ if (space) return -EINVAL;
+ if (conv == 's' && len) return -EINVAL;
+ }
+ while (walk-res < MSDOS_NAME_MAX) *walk++ = ' ';
+ for (reserved = reserved_names; *reserved; reserved++)
+ if (!strncmp(res,*reserved,8)) return -EINVAL;
+ return 0;
+}
+
+/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70) */
+unsigned int
+msdos_date_dos2unix(unsigned short time_val,unsigned short date)
+{
+ int month,year,secs;
+
+ month = ((date >> 5) & 15)-1;
+ year = date >> 9;
+ secs = (time_val & 31)*2+60*((time_val >> 5) & 63)+
+ (time_val >> 11)*3600+86400*
+ ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
+ month < 2 ? 1 : 0)+3653);
+ /* days since 1.1.70 plus 80's leap day */
+
+ return secs;
+}
+
+
+/* Convert linear UNIX date to a MS-DOS time/date pair */
+void msdos_date_unix2dos(int unix_date,
+ unsigned short *time_val,
+ unsigned short *date)
+{
+ int day,year,nl_day,month;
+
+ *time_val = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
+ (((unix_date/3600) % 24) << 11);
+ day = unix_date/86400-3652;
+ year = day/365;
+ if ((year+3)/4+365*year > day) year--;
+ day -= (year+3)/4+365*year;
+ if (day == 59 && !(year & 3)) {
+ nl_day = day;
+ month = 2;
+ }
+ else {
+ nl_day = (year & 3) || day <= 59 ? day : day-1;
+ for (month = 0; month < 12; month++)
+ if (day_n[month] > nl_day) break;
+ }
+ *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
+}
+
+
+/* msdos_get_token --
+ * Routine to get a token (name or separator) from the path.
+ *
+ * PARAMETERS:
+ * path - path to get token from
+ * ret_token - returned token
+ * token_len - length of returned token
+ *
+ * RETURNS:
+ * token type, token and token length
+ *
+ */
+msdos_token_types_t
+msdos_get_token(const char *path, char *ret_token, int *token_len)
+{
+ int rc = RC_OK;
+ register int i = 0;
+ msdos_token_types_t type = MSDOS_NAME;
+ char token[MSDOS_NAME_MAX_WITH_DOT+1];
+ register char c;
+
+ /*
+ * Copy a name into token. (Remember NULL is a token.)
+ */
+ c = path[i];
+ while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) )
+ {
+ token[i] = c;
+ if ( i == MSDOS_NAME_MAX_WITH_DOT )
+ return MSDOS_INVALID_TOKEN;
+ if ( !msdos_is_valid_name_char(c) )
+ return MSDOS_INVALID_TOKEN;
+ c = path [++i];
+ }
+
+ /*
+ * Copy a seperator into token.
+ */
+ if ( i == 0 )
+ {
+ token[i] = c;
+ if ( token[i] != '\0' )
+ {
+ i++;
+ type = MSDOS_CURRENT_DIR;
+ }
+ else
+ type = MSDOS_NO_MORE_PATH;
+ }
+ else if (token[ i-1 ] != '\0')
+ token[i] = '\0';
+
+ /*
+ * Set token_len to the number of characters copied.
+ */
+ *token_len = i;
+
+ /*
+ * If we copied something that was not a seperator see if
+ * it was a special name.
+ */
+ if ( type == MSDOS_NAME )
+ {
+ if ( strcmp( token, "..") == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOTDOT_NAME);
+ type = MSDOS_UP_DIR;
+ return type;
+ }
+
+ if ( strcmp( token, "." ) == 0 )
+ {
+ strcpy(ret_token, MSDOS_DOT_NAME);
+ type = MSDOS_CURRENT_DIR;
+ return type;
+ }
+
+ rc = msdos_format_name('r', token, *token_len, ret_token, 0);
+ if ( rc != RC_OK )
+ return MSDOS_INVALID_TOKEN;
+ }
+ ret_token[MSDOS_NAME_MAX] = '\0';
+ return type;
+}
+
+
+/* msdos_find_name --
+ * Find the node which correspondes to the name, open fat-file which
+ * correspondes to the found node and close fat-file which correspondes
+ * to the node we searched in.
+ *
+ * PARAMETERS:
+ * parent_loc - parent node description
+ * name - name to find
+ *
+ * RETURNS:
+ * RC_OK and updated 'parent_loc' on success, or -1 if error
+ * occured (errno set apropriately)
+ *
+ */
+int
+msdos_find_name(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ fat_auxiliary_t aux;
+ unsigned short time_val = 0;
+ unsigned short date = 0;
+ unsigned char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+
+ memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * find the node which correspondes to the name in the directory pointed by
+ * 'parent_loc'
+ */
+ rc = msdos_get_name_node(parent_loc, name, &aux, node_entry);
+ if (rc != RC_OK)
+ return rc;
+
+ /* open fat-file corresponded to the found node */
+ rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * I don't like this if, but: we should do it , or should write new file
+ * size and first cluster num to the disk after each write operation
+ * (even if one byte is written - that is TOO non-optimize) because
+ * otherwise real values of these fields stored in fat-file descriptor
+ * may be accidentely rewritten with wrong values stored on the disk
+ */
+ if (fat_fd->links_num == 1)
+ {
+ fat_fd->info_cln = aux.cln;
+ fat_fd->info_ofs = aux.ofs;
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
+ fat_fd->first_char = *MSDOS_DIR_NAME(node_entry);
+
+ time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
+ date = *MSDOS_DIR_WRITE_DATE(node_entry);
+
+ fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date));
+
+ if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
+ {
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ rc = fat_file_size(parent_loc->mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+ }
+ else
+ {
+ fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
+ fat_fd->fat_file_type = FAT_FILE;
+ fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
+ }
+
+ /* these data is not actual for zero-length fat-file */
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ if ((fat_fd->fat_file_size != 0) &&
+ (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
+ {
+ fat_fd->map.last_cln = fat_fd->cln;
+ }
+ else
+ {
+ fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
+ }
+ }
+
+ /* close fat-file corresponded to the node we searched in */
+ rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access);
+ if (rc != RC_OK)
+ {
+ fat_file_close(parent_loc->mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* update node_info_ptr field */
+ parent_loc->node_access = fat_fd;
+
+ return rc;
+}
+
+/* msdos_get_name_node --
+ * This routine is used in two ways: for a new mode creation (a) or for
+ * search the node which correspondes to the name parameter (b).
+ * In case (a) 'name' should be set up to NULL and 'name_dir_entry' should
+ * point to initialized 32 bytes structure described a new node.
+ * In case (b) 'name' should contain a valid string.
+ *
+ * (a): reading fat-file which correspondes to directory we are going to
+ * create node in. If free slot is found write contents of
+ * 'name_dir_entry' into it. If reach end of fat-file and no free
+ * slot found, write 32 bytes to the end of fat-file.
+ *
+ * (b): reading fat-file which correspondes to directory and trying to
+ * find slot with the name field == 'name' parameter
+ *
+ *
+ * PARAMETERS:
+ * parent_loc - node description to create node in or to find name in
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node (IN/OUT)
+ *
+ * RETURNS:
+ * RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if
+ * error occured (errno set apropriately)
+ *
+ */
+int
+msdos_get_name_node(
+ rtems_filesystem_location_info_t *parent_loc,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = parent_loc->node_access;
+ unsigned32 dotdot_cln = 0;
+
+ /* find name in fat-file which correspondes to the directory */
+ rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, name, paux,
+ name_dir_entry);
+ if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
+ return rc;
+
+ /* if we search for valid name and name not found -> return */
+ if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name != NULL))
+ return rc;
+
+ /*
+ * if we try to create new entry and the directory is not big enough
+ * currently - try to enlarge directory
+ */
+ if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name == NULL))
+ {
+ ret = fat_file_write(parent_loc->mt_entry, fat_fd,
+ fat_fd->fat_file_size,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ name_dir_entry);
+ if (ret == -1)
+ return -1;
+
+ /* on success directory is enlarged by a new cluster */
+ fat_fd->fat_file_size += fs_info->fat.vol.bpc;
+
+ /* get cluster num where a new node located */
+ rc = fat_file_ioctl(parent_loc->mt_entry, fat_fd, F_CLU_NUM,
+ fat_fd->fat_file_size - 1, &paux->cln);
+
+ if (rc != RC_OK)
+ return rc;
+
+ /*
+ * if new cluster allocated succesfully then new node is at very
+ * beginning of the cluster (offset is computed in bytes)
+ */
+ paux->ofs = 0;
+ return RC_OK;
+ }
+
+ /*
+ * if we have deal with ".." - it is a special case :(((
+ *
+ * Really, we should return cluster num and offset not of ".." slot, but
+ * slot which correspondes to real directory name.
+ */
+ if ((rc == RC_OK) && (name != NULL))
+ {
+ if (strncmp(name, MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry));
+
+ /* are we right under root dir ? */
+ if (dotdot_cln == 0)
+ {
+ /*
+ * we can relax about first_char field - it never should be
+ * used for root dir
+ */
+ paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
+ paux->ofs = 0;
+ }
+ else
+ {
+ rc = msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ parent_loc->mt_entry,
+ dotdot_cln,
+ paux,
+ name_dir_entry
+ );
+ if (rc != RC_OK)
+ return rc;
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+ * msdos_get_dotdot_dir_info_cluster_num_and_offset
+ *
+ * Unfortunately, in general, we cann't work here in fat-file ideologic
+ * (open fat_file "..", get ".." and ".", open "..", find an entry ...)
+ * because if we open
+ * fat-file ".." it may happend that we have two different fat-file
+ * descriptors ( for real name of directory and ".." name ) for a single
+ * file ( cluster num of both pointers to the same cluster )
+ * But...we do it because we protected by semaphore
+ *
+ */
+
+/* msdos_get_dotdot_dir_info_cluster_num_and_offset --
+ * Get cluster num and offset not of ".." slot, but slot which correspondes
+ * to real directory name.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cln - data cluster num extracted drom ".." slot
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured
+ * (errno set apropriately)
+ *
+ */
+int
+msdos_get_dotdot_dir_info_cluster_num_and_offset(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cln,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ fat_file_fd_t *fat_fd = NULL;
+ unsigned char dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned char cur_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
+ unsigned32 cl4find = 0;
+
+ memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ memset(cur_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+
+ /*
+ * open fat-file corresponded to ".."
+ */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ fat_fd->info_cln = paux->cln;
+ fat_fd->info_ofs = paux->ofs;
+ fat_fd->cln = cln;
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find "." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux,
+ dot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* find ".." node in opened directory */
+ rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux,
+ dotdot_node);
+
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
+
+ /* close fat-file corresponded to ".." directory */
+ rc = fat_file_close(mt_entry, fat_fd);
+ if ( rc != RC_OK )
+ return rc;
+
+ if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ {
+ /*
+ * we handle root dir for all FAT types in the same way with the
+ * ordinary directories ( through fat_file_* calls )
+ */
+ paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
+ paux->ofs = 0;
+ }
+
+ /* open fat-file corresponded to second ".." */
+ rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
+ if (rc != RC_OK)
+ return rc;
+
+ fat_fd->info_cln = paux->cln;
+ fat_fd->info_ofs = paux->ofs;
+
+ if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
+ fat_fd->cln = fs_info->fat.vol.rdir_cl;
+ else
+ fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
+
+ fat_fd->fat_file_type = FAT_DIRECTORY;
+ fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
+
+ fat_fd->map.file_cln = 0;
+ fat_fd->map.disk_cln = fat_fd->cln;
+
+ rc = fat_file_size(mt_entry, fat_fd);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+
+ /* in this directory find slot with specified cluster num */
+ rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
+ paux, dir_entry);
+ if (rc != RC_OK)
+ {
+ fat_file_close(mt_entry, fat_fd);
+ return rc;
+ }
+ rc = fat_file_close(mt_entry, fat_fd);
+ return rc;
+}
+
+
+/* msdos_set_dir_wrt_time_and_date --
+ * Write last write date and time for a file to the disk (to corresponded
+ * 32bytes node)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_dir_wrt_time_and_date(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned short time_val;
+ unsigned short date;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ msdos_date_unix2dos(fat_fd->mtime, &time_val, &date);
+
+ /*
+ * calculate input for _fat_block_write: convert (cluster num, offset) to
+ * (sector num, new offset)
+ */
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ /* byte points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ time_val = CT_LE_W(time_val);
+ ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET,
+ 2, (char *)(&time_val));
+ date = CT_LE_W(date);
+ ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET,
+ 2, (char *)(&date));
+
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_set_first_cluster_num --
+ * Write number of first cluster of the file to the disk (to corresponded
+ * 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_set_first_cluster_num(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret1 = 0, ret2 = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 new_cln = fat_fd->cln;
+ unsigned16 le_cl_low = 0;
+ unsigned16 le_cl_hi = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ /*
+ * calculate input for _fat_block_write: convert (cluster num, offset) to
+ * (sector num, new offset)
+ */
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ /* byte from points to start of 32bytes structure */
+ byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
+
+ le_cl_low = CT_LE_W((unsigned16)(new_cln & 0x0000FFFF));
+ ret1 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
+ (char *)(&le_cl_low));
+ le_cl_hi = CT_LE_W((unsigned16)((new_cln & 0xFFFF0000) >> 16));
+ ret2 = _fat_block_write(mt_entry, sec,
+ byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
+ (char *)(&le_cl_hi));
+ if ( (ret1 < 0) || (ret2 < 0) )
+ return -1;
+
+ return RC_OK;
+}
+
+
+/* msdos_set_file size --
+ * Write file size of the file to the disk (to corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately).
+ *
+ */
+int
+msdos_set_file_size(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 le_new_length = 0;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
+ sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
+ byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1));
+
+ le_new_length = CT_LE_L((fat_fd->fat_file_size));
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
+ (char *)(&le_new_length));
+ if ( ret < 0 )
+ return -1;
+
+ return RC_OK;
+}
+
+/*
+ * We should not check whether this routine is called for root dir - it
+ * never can happend
+ */
+
+/* msdos_set_first_char4file_name --
+ * Write first character of the name of the file to the disk (to
+ * corresponded 32bytes slot)
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * cl - number of cluster
+ * ofs - offset inside cluster
+ * fchar - character to set up
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured (errno set apropriately)
+ *
+ */
+int
+msdos_set_first_char4file_name(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ unsigned32 cl,
+ unsigned32 ofs,
+ unsigned char fchar
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 sec = 0;
+ unsigned32 byte = 0;
+
+ sec = fat_cluster_num_to_sector_num(mt_entry, cl);
+ sec += (ofs >> fs_info->fat.vol.sec_log2);
+ byte = (ofs & (fs_info->fat.vol.bps - 1));
+
+ ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1,
+ &fchar);
+ if ( ret < 0)
+ return -1;
+
+ return RC_OK;
+}
+
+/* msdos_dir_is_empty --
+ * Check whether directory which correspondes to the fat-file descriptor is
+ * empty.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * ret_val - placeholder for result
+ *
+ * RETURNS:
+ * RC_OK on success, or -1 if error occured
+ *
+ */
+int
+msdos_dir_is_empty(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ rtems_boolean *ret_val
+ )
+{
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 j = 0, i = 0;
+
+ /* dir is not empty */
+ *ret_val = FALSE;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
+ fs_info->fat.vol.bps,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ assert(ret == fs_info->fat.vol.bps);
+
+ for (i = 0;
+ i < fs_info->fat.vol.bps;
+ i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0) ||
+ (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
+ MSDOS_DOTDOT_NAME,
+ MSDOS_SHORT_NAME_LEN) == 0))
+ continue;
+
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ {
+ *ret_val = TRUE;
+ return RC_OK;
+ }
+ return RC_OK;
+ }
+ j++;
+ }
+ *ret_val = TRUE;
+ return RC_OK;
+}
+
+
+/* msdos_find_name_in_fat_file --
+ * This routine is used in two ways: for a new mode creation (a) or for
+ * search the node which correspondes to the 'name' parameter (b).
+ * In case (a) name should be set up to NULL and 'name_dir_entry' should
+ * point to initialized 32 bytes structure described a new node.
+ * In case (b) 'name' should contain a valid string.
+ *
+ * (a): reading fat-file corresponded to directory we are going to create
+ * node in. If found free slot write contents of name_dir_entry into
+ * it.
+ *
+ * (b): reading fat-file corresponded to directory and trying to find slot
+ * with the name field == name parameter
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * name - NULL or name to find
+ * paux - identify a node location on the disk -
+ * number of cluster and offset inside the cluster
+ * name_dir_entry - node to create/placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured (errno set
+ * appropriately)
+ *
+ */
+int
+msdos_find_name_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ char *name,
+ fat_auxiliary_t *paux,
+ char *name_dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 i = 0, j = 0;
+ unsigned32 bts2rd = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
+ bts2rd = fat_fd->fat_file_size;
+ else
+ bts2rd = fs_info->fat.vol.bpc;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ set_errno_and_return_minus_one(EIO);
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* is the entry empty ? */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
+ ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY))
+ {
+ /* whether we are looking for an empty entry */
+ if (name == NULL)
+ {
+ /* get current cluster number */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ /* offset is computed in bytes */
+ paux->ofs = i;
+
+ /* write new node entry */
+ ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
+ name_dir_entry);
+ if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ return -1;
+
+ /*
+ * we don't update fat_file_size here - it should not
+ * increase
+ */
+ return RC_OK;
+ }
+
+ /*
+ * if name != NULL and there is no more entries in the
+ * directory - return name-not-found
+ */
+ if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY))
+ return MSDOS_NAME_NOT_FOUND_ERR;
+ }
+ else
+ {
+ /* entry not empty and name != NULL -> compare names */
+ if (name != NULL)
+ {
+ if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name,
+ MSDOS_SHORT_NAME_LEN) == 0)
+ {
+ /*
+ * we get the entry we looked for - fill auxiliary
+ * structure and copy all 32 bytes of the entry
+ */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
+ j * bts2rd, &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ /* offset is computed in bytes */
+ paux->ofs = i;
+ memcpy(name_dir_entry,(fs_info->cl_buf + i),
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
+
+/* msdos_find_node_by_cluster_num_in_fat_file --
+ * Find node with specified number of cluster in fat-file.
+ *
+ * PARAMETERS:
+ * mt_entry - mount table entry
+ * fat_fd - fat-file descriptor
+ * cl4find - number of cluster to find
+ * paux - identify a node location on the disk -
+ * cluster num and offset inside the cluster
+ * dir_entry - placeholder for found node
+ *
+ * RETURNS:
+ * RC_OK on success, or error code if error occured
+ *
+ */
+int
+msdos_find_node_by_cluster_num_in_fat_file(
+ rtems_filesystem_mount_table_entry_t *mt_entry,
+ fat_file_fd_t *fat_fd,
+ unsigned32 cl4find,
+ fat_auxiliary_t *paux,
+ char *dir_entry
+ )
+{
+ int rc = RC_OK;
+ ssize_t ret = 0;
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ unsigned32 bts2rd = 0;
+ unsigned32 i = 0, j = 0;
+
+ if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
+ (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
+ bts2rd = fat_fd->fat_file_size;
+ else
+ bts2rd = fs_info->fat.vol.bpc;
+
+ while ((ret = fat_file_read(mt_entry, fat_fd, j * bts2rd, bts2rd,
+ fs_info->cl_buf)) != FAT_EOF)
+ {
+ if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
+ set_errno_and_return_minus_one( EIO );
+
+ assert(ret == bts2rd);
+
+ for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ {
+ /* if this and all rest entries are empty - return not-found */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
+ return MSDOS_NAME_NOT_FOUND_ERR;
+
+ /* if this entry is empty - skip it */
+ if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
+ MSDOS_THIS_DIR_ENTRY_EMPTY)
+ continue;
+
+ /* if get a non-empty entry - compare clusters num */
+ if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find)
+ {
+ /* on success fill aux structure and copy all 32 bytes */
+ rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd,
+ &paux->cln);
+ if (rc != RC_OK)
+ return rc;
+
+ paux->ofs = i;
+ memcpy(dir_entry, fs_info->cl_buf + i,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ return RC_OK;
+ }
+ }
+ j++;
+ }
+ return MSDOS_NAME_NOT_FOUND_ERR;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_mknod.c b/cpukit/libfs/src/dosfs/msdos_mknod.c
new file mode 100644
index 0000000000..5e32dbf3bf
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_mknod.c
@@ -0,0 +1,90 @@
+/*
+ * Routine for node creation in MSDOS filesystem.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_mknod --
+ * The following function checks spelling and formats name for a new node,
+ * determines type of the node to be created and creates it.
+ *
+ * PARAMETERS:
+ * token - non-formatted name of a new node
+ * mode - node type
+ * dev - dev
+ * pathloc - parent directory description
+ *
+ * RETURNS:
+ * RC_OK on succes, or -1 if error occured and set errno
+ *
+ */
+int
+msdos_mknod(
+ const char *token,
+ mode_t mode,
+ dev_t dev,
+ rtems_filesystem_location_info_t *pathloc
+ )
+{
+ int rc = RC_OK;
+ rtems_status_code sc = RTEMS_SUCCESSFUL;
+ msdos_fs_info_t *fs_info = pathloc->mt_entry->fs_info;
+ msdos_token_types_t type = 0;
+ char new_name[ MSDOS_NAME_MAX + 1 ];
+ int len;
+
+ /* check spelling and format new node name */
+ msdos_get_token(token, new_name, &len);
+
+ /*
+ * Figure out what type of msdos node this is.
+ */
+ if (S_ISDIR(mode))
+ {
+ type = MSDOS_DIRECTORY;
+ }
+ else if (S_ISREG(mode))
+ {
+ type = MSDOS_REGULAR_FILE;
+ }
+ else
+ set_errno_and_return_minus_one(EINVAL);
+
+ sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
+ MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
+ if (sc != RTEMS_SUCCESSFUL)
+ set_errno_and_return_minus_one(EIO);
+
+ /* Create an MSDOS node */
+ rc = msdos_creat_node(pathloc, type, new_name, mode);
+
+ rtems_semaphore_release(fs_info->vol_sema);
+ return rc;
+}
diff --git a/cpukit/libfs/src/dosfs/msdos_node_type.c b/cpukit/libfs/src/dosfs/msdos_node_type.c
new file mode 100644
index 0000000000..517dabda3f
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_node_type.c
@@ -0,0 +1,58 @@
+/*
+ * The following returns the type of node that the loc refers to.
+ *
+ * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
+ * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.OARcorp.com/rtems/license.html.
+ *
+ * @(#) $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <rtems.h>
+
+#include <rtems/libio_.h>
+
+#include "fat.h"
+#include "fat_fat_operations.h"
+#include "fat_file.h"
+
+#include "msdos.h"
+
+/* msdos_node_type --
+ * Determine type of the node that the pathloc refers to.
+ *
+ * PARAMETERS:
+ * pathloc - node description
+ *
+ * RETURNS:
+ * node type
+ *
+ */
+rtems_filesystem_node_types_t
+msdos_node_type(rtems_filesystem_location_info_t *pathloc)
+{
+ fat_file_fd_t *fat_fd;
+
+ /*
+ * we don't need to obtain the volume semaphore here because node_type_h
+ * call always follows evalpath_h call(hence link increment occured) and
+ * hence node_access memory can't be freed during processing node_type_h
+ * call
+ */
+ fat_fd = pathloc->node_access;
+
+ return fat_fd->fat_file_type;
+}
diff --git a/cpukit/libfs/wrapup/Makefile.am b/cpukit/libfs/wrapup/Makefile.am
index 5dfd76e83d..13406dcb5f 100644
--- a/cpukit/libfs/wrapup/Makefile.am
+++ b/cpukit/libfs/wrapup/Makefile.am
@@ -13,7 +13,9 @@ include $(top_srcdir)/../../../automake/lib.am
IMFSLIB = ../src/imfs/$(ARCH)/libimfs.a
-TMP_LIBS = $(IMFSLIB)
+DOSFSLIB = ../src/dosfs/$(ARCH)/libdosfs.a
+
+TMP_LIBS = $(IMFSLIB) $(DOSFSLIB)
$(PROJECT_RELEASE)/lib/$(LIBNAME)$(LIB_VARIANT).a: $(LIB)
$(INSTALL_DATA) $< $@