Index: cpukit/libfs/Makefile.am
===================================================================
--- cpukit/libfs/Makefile.am	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/Makefile.am	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -82,4 +82,5 @@
     src/dosfs/msdos_mknod.c src/dosfs/msdos_node_type.c \
     src/dosfs/msdos_rmnod.c src/dosfs/msdos_statvfs.c \
+    src/dosfs/msdos_conv_default.c \
     src/dosfs/msdos_conv.c src/dosfs/msdos.h src/dosfs/msdos_format.c \
     src/dosfs/dosfs.h src/dosfs/msdos_rename.c
Index: cpukit/libfs/src/dosfs/dosfs.h
===================================================================
--- cpukit/libfs/src/dosfs/dosfs.h	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/dosfs.h	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -1,8 +1,8 @@
 /**
- * @file rtems/dosfs.h
- *
- * @brief Application Interface to MSDOS Filesystem
- *
- * @ingroup rtems_msdos_format
+ * @file
+ *
+ * @brief Application Interface to FAT Filesystem
+ *
+ * @ingroup DOSFS
  */
 
@@ -11,4 +11,7 @@
  *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
  *
+ *  Modifications to support UTF-8 in the file system are
+ *  Copyright (c) 2013 embedded brains GmbH.
+ *
  *  The license and distribution terms for this file may be
  *  found in the file LICENSE in this distribution or at
@@ -26,4 +29,168 @@
 #endif
 
+typedef struct rtems_dosfs_convert_control rtems_dosfs_convert_control;
+
+/**
+ * @brief Converts from UTF-8 into a specific code page.
+ *
+ * @param[in/out] self The convert control.
+ * @param[in] src A well-formed UTF-8 string to be converted.
+ * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
+ * @param[out] dst The address the converted string will get copied to.
+ * @param[in/out] dst_size The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ *
+ * @retval 0 Successful operation.
+ * @retval EINVAL Conversion was successful, but is not reversible.
+ * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
+ */
+typedef int (*rtems_dosfs_utf8_to_codepage)(
+  rtems_dosfs_convert_control *self,
+  const uint8_t               *src,
+  size_t                       src_size,
+  char                        *dst,
+  size_t                      *dst_size
+);
+
+/**
+ * @brief Converts from a specific code page into UTF-8
+ *
+ * @param[in/out] self The convert control.
+ * @param[in] src A well-formed string in code page format.
+ * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
+ * @param[out] dst The address the converted string will get copied to.
+ * @param[in/out] dst_size The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ *
+ * @retval 0 Successful operation.
+ * @retval EINVAL Conversion was successful, but is not reversible.
+ * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
+ */
+typedef int (*rtems_dosfs_codepage_to_utf8)(
+  rtems_dosfs_convert_control *self,
+  const char                  *src,
+  size_t                       src_size,
+  uint8_t                     *dst,
+  size_t                      *dst_size
+);
+
+/**
+ * @brief Converts from UTF-8 to UTF-16
+ *
+ * @param[in/out] self The convert control.
+ * @param[in] src A well-formed UTF-8 string to be converted.
+ * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
+ * @param[out] dst The address the converted string will get copied to
+ * @param[in/out] dst_size The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ *
+ * @retval 0 Successful operation.
+ * @retval EINVAL Conversion was successful, but is not reversible.
+ * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
+ */
+typedef int (*rtems_dosfs_utf8_to_utf16)(
+  rtems_dosfs_convert_control *self,
+  const uint8_t               *src,
+  size_t                       src_size,
+  uint16_t                    *dst,
+  size_t                      *dst_size
+);
+
+/**
+ * @brief Converts from UTF-16 to UTF-8.
+ *
+ * @param[in/out] self The convert control.
+ * @param[in] src A well-formed UTF-16 string to be converted.
+ * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
+ * @param[out] dst The address the converted string will get copied to.
+ * @param[in/out] dst_size The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer
+ *
+ * @retval 0 Successful operation.
+ * @retval EINVAL Conversion was successful, but is not reversible.
+ * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
+ */
+typedef int (*rtems_dosfs_utf16_to_utf8)(
+  rtems_dosfs_convert_control *self,
+  const uint16_t              *src,
+  size_t                       src_size,
+  uint8_t                     *dst,
+  size_t                      *dst_size
+);
+
+/**
+ * @brief Converts from UTF-8 to Normalized Form Canonical Decomposition.
+ *
+ * Does canonical decomposition of the UTF-8 string and in addition
+ * also converts upper case alphabetic characters to lower case characters
+ *
+ * @param[in/out] self The convert control.
+ * @param[in] src A well-formed UTF-8 string to be normalized and fold.
+ * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
+ * @param[out] dst The address the normalized and fold string will get
+ * copied to.
+ * @param[in/out] dst_size The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ *
+ * @retval 0 Successful operation.
+ * @retval EINVAL Conversion failed.
+ * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
+ * @retval EOVERFLOW Conversion failed.
+ * @retval ENOENT Conversion failed.
+ */
+typedef int (*rtems_dosfs_utf8_normalize_and_fold)(
+  rtems_dosfs_convert_control *self,
+  const uint8_t               *src,
+  size_t                       src_size,
+  uint8_t                     *dst,
+  size_t                      *dst_size
+);
+
+/**
+ * @brief Destroys a convert control structure.
+ *
+ * @param[in/out] self The convert control for destruction.
+ */
+typedef void (*rtems_dosfs_convert_destroy)(
+  rtems_dosfs_convert_control *self
+);
+
+/**
+ * @brief FAT filesystem convert handler.
+ */
+typedef struct {
+  rtems_dosfs_utf8_to_codepage        utf8_to_codepage;
+  rtems_dosfs_codepage_to_utf8        codepage_to_utf8;
+  rtems_dosfs_utf8_to_utf16           utf8_to_utf16;
+  rtems_dosfs_utf16_to_utf8           utf16_to_utf8;
+  rtems_dosfs_utf8_normalize_and_fold utf8_normalize_and_fold;
+  rtems_dosfs_convert_destroy         destroy;
+} rtems_dosfs_convert_handler;
+
+typedef struct {
+  void   *data;
+  size_t  size;
+} rtems_dosfs_buffer;
+
+/**
+ * @brief FAT filesystem convert control.
+ *
+ * Short file names are stored in the code page format.  Long file names are
+ * stored as little-endian UTF-16.  The convert control determines the format
+ * conversions to and from the POSIX file name strings.
+ */
+struct rtems_dosfs_convert_control {
+  const rtems_dosfs_convert_handler *handler;
+  rtems_dosfs_buffer                 buffer;
+};
+
+/**
+ * @defgroup DOSFS FAT Filesystem Support
+ *
+ * @ingroup FileSystemTypesAndMount
+ *
+ * @{
+ */
+
 /**
  * @brief Semaphore count per FAT filesystem instance.
@@ -33,14 +200,25 @@
 #define RTEMS_DOSFS_SEMAPHORES_PER_INSTANCE 1
 
-int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
-                           const void                           *data);
-
-/**
- * @defgroup rtems_msdos_format DOSFS Support
- *
- * @ingroup FileSystemTypesAndMount
- *
- */
-/**@{**/
+/**
+ * @brief FAT filesystem mount options.
+ */
+typedef struct {
+  /**
+   * @brief Converter implementation for new filesystem instance.
+   *
+   * @see rtems_dosfs_create_default_converter().
+   */
+  rtems_dosfs_convert_control *converter;
+} rtems_dosfs_mount_options;
+
+/**
+ * @brief Allocates and initializes a default converter.
+ *
+ * @retval NULL Something failed.
+ * @retval other Pointer to initialized converter.
+ *
+ * @see rtems_dosfs_mount_options and mount().
+ */
+rtems_dosfs_convert_control *rtems_dosfs_create_default_converter(void);
 
 #define MSDOS_FMT_INFO_LEVEL_NONE   (0)
@@ -132,4 +310,7 @@
 /** @} */
 
+int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
+                           const void                           *data);
+
 #ifdef __cplusplus
 }
Index: cpukit/libfs/src/dosfs/msdos.h
===================================================================
--- cpukit/libfs/src/dosfs/msdos.h	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos.h	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -10,4 +10,7 @@
  *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
  *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ *  Modifications to support UTF-8 in the file system are
+ *  Copyright (c) 2013 embedded brains GmbH.
  *
  *  The license and distribution terms for this file may be
@@ -21,4 +24,5 @@
 #include <rtems.h>
 #include <rtems/libio_.h>
+#include <rtems/dosfs.h>
 
 #include "fat.h"
@@ -68,4 +72,6 @@
                                                             * for anything
                                                             */
+
+    rtems_dosfs_convert_control      *converter;
 } msdos_fs_info_t;
 
@@ -184,4 +190,6 @@
  *  Macros for names parsing and formatting
  */
+#define MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR  4
+#define MSDOS_NAME_MIN_UTF8_BYTES_PER_CHAR  1
 
 #define MSDOS_SHORT_BASE_LEN             8  /* 8 characters */
@@ -191,7 +199,18 @@
 #define MSDOS_NAME_MAX_LNF_LEN           (255)
 #define MSDOS_NAME_MAX                   MSDOS_SHORT_NAME_LEN
+#define MSDOS_NAME_MAX_UTF8_SFN_BYTES    (MSDOS_NAME_MAX *\
+                                         MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
 #define MSDOS_NAME_MAX_WITH_DOT          (MSDOS_NAME_MAX + 1)
+#define MSDOS_SFN_MAX_WITH_DOT_UTF8_BYTES (MSDOS_NAME_MAX_WITH_DOT *\
+                                           MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
 #define MSDOS_NAME_MAX_LFN_WITH_DOT      (260)
 
+#define MSDOS_NAME_LFN_BYTES_PER_CHAR    (2)
+#define MSDOS_NAME_MAX_LFN_BYTES         (MSDOS_NAME_MAX_LFN_WITH_DOT *\
+                                          MSDOS_NAME_LFN_BYTES_PER_CHAR)
+#define MSDOS_NAME_MAX_UTF8_LFN_BYTES    (MSDOS_NAME_MAX_LFN_WITH_DOT *\
+                                          MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
+#define MSDOS_ENTRY_LFN_UTF8_BYTES       (MSDOS_LFN_LEN_PER_ENTRY *\
+                                          MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
 
 extern const char *const MSDOS_DOT_NAME;    /* ".", padded to MSDOS_NAME chars */
@@ -310,5 +329,6 @@
   const rtems_filesystem_operations_table *op_table,
   const rtems_filesystem_file_handlers_r  *file_handlers,
-  const rtems_filesystem_file_handlers_r  *directory_handlers
+  const rtems_filesystem_file_handlers_r  *directory_handlers,
+  rtems_dosfs_convert_control             *converter
 );
 
@@ -388,8 +408,50 @@
 int msdos_dir_info_remove(rtems_filesystem_location_info_t *pathloc);
 
-msdos_name_type_t msdos_long_to_short(const char *lfn, int lfn_len,
+ssize_t
+msdos_format_dirent_with_dot(char *dst,const char *src);
+
+msdos_name_type_t msdos_long_to_short(rtems_dosfs_convert_control *converter,
+                                      const char *lfn, int lfn_len,
                                       char* sfn, int sfn_len);
 
-int msdos_filename_unix2dos(const char *un, int unlen, char *dn);
+ssize_t
+msdos_filename_utf8_to_short_name_for_compare (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    void                            *short_name,
+    const size_t                     short_name_size);
+
+ssize_t
+msdos_filename_utf8_to_short_name_for_save (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    void                            *short_name,
+    const size_t                     short_name_size);
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_compare (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    uint8_t                         *long_name,
+    const size_t                     long_name_size);
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_save (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    uint16_t                        *long_name,
+    const size_t                     long_name_size);
+
+ssize_t
+msdos_get_utf16_string_from_long_entry (
+  const char                 *entry,
+  uint16_t                   *entry_string_buf,
+  const size_t                buf_size,
+  bool                        is_first_entry
+);
 
 void msdos_date_unix2dos(
@@ -431,5 +493,5 @@
     fat_file_fd_t                        *fat_fd,
     bool                                  create_node,
-    const char                           *name,
+    const uint8_t                        *name_utf8,
     int                                   name_len,
     msdos_name_type_t                     name_type,
Index: cpukit/libfs/src/dosfs/msdos_conv.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_conv.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_conv.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -23,4 +23,7 @@
  *
  * October 1992
+ *
+ * Modifications to support UTF-8 in the file system are
+ * Copyright (c) 2013 embedded brains GmbH.
  */
 
@@ -29,4 +32,5 @@
 #endif
 
+#include <ctype.h>
 #include <rtems.h>
 #include "msdos.h"
@@ -34,4 +38,20 @@
 /* #define SECONDSPERDAY (24 * 60 * 60) */
 #define SECONDSPERDAY ((uint32_t) 86400)
+
+#define UTF8_MAX_CHAR_SIZE    4
+#define UTF8_NULL             0x00
+#define UTF8_NULL_SIZE        1
+#define UTF8_BLANK            0x20
+#define UTF8_BLANK_SIZE       1
+#define UTF8_FULL_STOP        0x2e
+#define UTF8_FULL_STOP_SIZE   1
+
+#define UTF16_MAX_CHAR_SIZE   4
+#define UTF16_NULL            CT_LE_W( 0x0000 )
+#define UTF16_NULL_SIZE       2
+#define UTF16_BLANK           CT_LE_W( 0x0020 )
+#define UTF16_BLANK_SIZE      2
+#define UTF16_FULL_STOP       CT_LE_W( 0x002e )
+#define UTF16_FULL_STOP_SIZE  2
 
 /*
@@ -175,149 +195,484 @@
 }
 
-static const uint8_t msdos_map[] = {
+
+static const uint8_t codepage_valid_char_map[] = {
     0,    0,    0,    0,    0,    0,    0,    0,    /* 00-07 */
     0,    0,    0,    0,    0,    0,    0,    0,    /* 08-0f */
     0,    0,    0,    0,    0,    0,    0,    0,    /* 10-17 */
     0,    0,    0,    0,    0,    0,    0,    0,    /* 18-1f */
-    0,    '!',  0,    '#',  '$',  '%',  '&',  '\'', /* 20-27 */
-    '(',  ')',  0,    '+',  0,    '-',  0,    0,    /* 28-2f */
-    '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  /* 30-37 */
-    '8',  '9',  0,    0,    0,    0,    0,    0,    /* 38-3f */
-    '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 40-47 */
-    'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  /* 48-4f */
-    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  /* 50-57 */
-    'X',  'Y',  'Z',  0,    0,    0,    '^',  '_',  /* 58-5f */
-    '`',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 60-67 */
-    'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  /* 68-6f */
-    'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  /* 70-77 */
-    'X',  'Y',  'Z',  '{',  0,    '}',  '~',  0,    /* 78-7f */
-    0,    0,    0,    0,    0,    0,    0,    0,    /* 80-87 */
-    0,    0,    0,    0,    0,    0,    0,    0,    /* 88-8f */
-    0,    0,    0,    0,    0,    0,    0,    0,    /* 90-97 */
-    0,    0,    0,    0,    0,    0,    0,    0,    /* 98-9f */
-    0,    0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */
-    0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */
-    0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */
-    0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */
-    0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */
-    0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */
-    0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */
-    0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */
-    0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */
-    0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */
-    0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */
-    0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */
-#if OLD_TABLE
-/* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 20 */ 0x00, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, /*  !"#$%&' */
-/* 28 */ 0x28, 0x29, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, /* ()*+,-./ */
-/* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 01234567 */
-/* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 89:;<=>? */
-/* 40 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
-/* 48 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* HIJKLMNO */
-/* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* PQRSTUVW */
-/* 58 */ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x00, 0x5E, 0x5F, /* XYZ[\]^_ */
-/* 60 */ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */
-/* 68 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* hijklmno */
-/* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* pqrstuvw */
-/* 78 */ 0x58, 0x59, 0x5A, 0x5B, 0x7C, 0x00, 0x7E, 0x00, /* xyz{|}~  */
-/* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* 98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* A8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* B8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* C8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* D8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* E8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-/* F8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-#endif
+    0x20, 0x21, 0,    0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
+    0x28, 0x29, 0,    0,    0,    0x2d,  0,    0,   /* 28-2f */
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
+    0x38, 0x39, 0,    0,    0,    0,    0,    0,    /* 38-3f */
+    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
+    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
+    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
+    0x58, 0x59, 0x5a, 0,    0,    0,    0x5e, 0x5f, /* 58-5f */
+    0x60, 0,    0,    0,    0,    0,    0,    0,    /* 60-67 */
+    0,    0,    0,    0,    0,    0,    0,    0,    /* 68-6f */
+    0,    0,    0,    0,    0,    0,    0,    0,    /* 70-77 */
+    0,    0,    0,    0x7b, 0,    0x7d, 0x7e, 0,    /* 78-7f */
+    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
+    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
+    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
+    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
+    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
+    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
+    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
+    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
+    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* c0-c7 */
+    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* c8-cf */
+    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* d0-d7 */
+    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* d8-df */
+    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
+    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
+    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
+    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff  /* f8-ff */
 };
-/*
- * Convert a unix filename to a DOS filename. Return -1 if wrong name is
- * supplied.
- */
-int
-msdos_filename_unix2dos(const char *un, int unlen, char *dn)
-{
-	int i;
-	uint8_t c;
-
-	/*
-	 * Fill the dos filename string with blanks. These are DOS's pad
-	 * characters.
-	 */
-	for (i = 0; i <= 10; i++)
-		dn[i] = ' ';
-
-	/*
-	 * The filenames "." and ".." are handled specially, since they
-	 * don't follow dos filename rules.
-	 */
-	if (un[0] == '.' && unlen == 1) {
-		dn[0] = '.';
-		return 0;
-	}
-	if (un[0] == '.' && un[1] == '.' && unlen == 2) {
-		dn[0] = '.';
-		dn[1] = '.';
-		return 0;
-	}
-
+
+static uint16_t
+msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
+{
+  uint16_t retval    = 0x0000;
+  uint16_t char_num  = CF_LE_W( utf16_character );
+
+  if ( char_num <= 0x00ff ) {
+    switch ( char_num )
+    {
+      case 0x002b: /* '+' */
+      case 0x002c: /* ',' */
+      case 0x002e: /* '.' */
+      case 0x003b: /* ';' */
+      case 0x003d: /* '=' */
+      case 0x005b: /* '[' */
+      case 0x005d: /* ']' */
+      case 0x0061: /* 'a' */
+      case 0x0062: /* 'b' */
+      case 0x0063: /* 'c' */
+      case 0x0064: /* 'd' */
+      case 0x0065: /* 'e' */
+      case 0x0066: /* 'f' */
+      case 0x0067: /* 'g' */
+      case 0x0068: /* 'h' */
+      case 0x0069: /* 'i' */
+      case 0x006a: /* 'j' */
+      case 0x006b: /* 'k' */
+      case 0x006c: /* 'l' */
+      case 0x006d: /* 'm' */
+      case 0x006e: /* 'n' */
+      case 0x006f: /* 'o' */
+      case 0x0070: /* 'p' */
+      case 0x0071: /* 'q' */
+      case 0x0072: /* 'r' */
+      case 0x0073: /* 's' */
+      case 0x0074: /* 't' */
+      case 0x0075: /* 'u' */
+      case 0x0076: /* 'v' */
+      case 0x0077: /* 'w' */
+      case 0x0078: /* 'x' */
+      case 0x0079: /* 'y' */
+      case 0x007a: /* 'z' */
+        retval = char_num;
+      break;
+      default:
+        retval = codepage_valid_char_map[char_num];
+      break;
+    }
+  }
+  else
+    retval = char_num;
+
+  return CT_LE_W( retval );
+}
+
+static char
+msdos_get_valid_codepage_filename_character (const uint8_t character)
+{
+  return codepage_valid_char_map[(unsigned int)character];
+}
+
+static ssize_t
+msdos_filename_process_dot_names (const uint8_t *src_name,
+                                  const size_t   src_size,
+                                  uint8_t       *dest_name,
+                                  const size_t   dest_size)
+{
+  ssize_t returned_size = 0;
+  int     eno           = 0;
   /*
-   * Remove any dots from the start of a file name.
+    * The filenames "." and ".." are handled specially, since they
+    * don't follow dos filename rules.
+    */
+   if (    src_name[0] == UTF8_FULL_STOP
+        && src_size    == UTF8_FULL_STOP_SIZE) {
+     if (dest_size >= UTF8_FULL_STOP_SIZE) {
+       dest_name[0]  = UTF8_FULL_STOP;
+       returned_size = UTF8_FULL_STOP_SIZE;
+     }
+     else
+       eno = ENAMETOOLONG;
+   }
+   else if (    eno           == 0
+             && src_name[0]   == UTF8_FULL_STOP
+             && src_name[1]   == UTF8_FULL_STOP
+             && src_size      == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
+     if (dest_size >= 2 * UTF8_FULL_STOP_SIZE) {
+       dest_name[0]  = UTF8_FULL_STOP;
+       dest_name[1]  = UTF8_FULL_STOP;
+       returned_size = 2 * UTF8_FULL_STOP_SIZE;
+     }
+     else
+       eno = ENAMETOOLONG;
+   }
+
+   if (eno != 0) {
+     errno         = eno;
+     returned_size = -1;
+   }
+
+   return returned_size;
+}
+
+static ssize_t
+msdos_filename_delete_trailing_dots (const uint8_t *filename_utf8,
+                                     const size_t   filename_size)
+{
+  ssize_t      size_returned = filename_size;
+  unsigned int i;
+
+  /*
+   * Remove any dots from the end of a file name.
    */
-	while (unlen && (*un == '.')) {
-		un++;
-		unlen--;
-	}
-
-	/*
-	 * Copy the unix filename into the dos filename string upto the end
-	 * of string, a '.', or 8 characters. Whichever happens first stops
-	 * us. This forms the name portion of the dos filename. Fold to
-	 * upper case.
-	 */
-	for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
-    if (msdos_map[c] == 0)
-      break;
-		dn[i] = msdos_map[c];
-		un++;
-		unlen--;
-	}
-
-	/*
-	 * Strip any further characters up to a '.' or the end of the
-	 * string.
-	 */
-	while (unlen && (c = *un)) {
-		un++;
-		unlen--;
-		/* Make sure we've skipped over the dot before stopping. */
-		if (c == '.')
-			break;
-	}
-
-	/*
-	 * Copy in the extension part of the name, if any. Force to upper
-	 * case. Note that the extension is allowed to contain '.'s.
-	 * Filenames in this form are probably inaccessable under dos.
-	 */
-	for (i = 8; i <= 10 && unlen && (c = *un); i++) {
-    if (msdos_map[c] == 0)
-      break;
-    dn[i] = msdos_map[c];
-		un++;
-		unlen--;
-	}
-	return 0;
-}
+  for ( i = size_returned - UTF8_FULL_STOP_SIZE;
+           size_returned >= UTF8_FULL_STOP_SIZE
+        && filename_utf8[i] == UTF8_FULL_STOP;) {
+    size_returned -= UTF8_FULL_STOP_SIZE;
+    i             -= UTF8_FULL_STOP_SIZE;
+  }
+
+  return size_returned;
+}
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_compare (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    uint8_t                         *long_name,
+    const size_t                     long_name_size)
+  {
+    ssize_t        returned_size = 0;
+    int            eno           = 0;
+    size_t         name_size;
+    size_t         dest_size     = long_name_size;
+
+    returned_size = msdos_filename_process_dot_names (
+      utf8_name,
+      utf8_name_size,
+      long_name,
+      long_name_size);
+
+    if (returned_size == 0) {
+      name_size = msdos_filename_delete_trailing_dots (
+        &utf8_name[0],
+        utf8_name_size);
+      if (name_size > 0) {
+        eno = (*converter->handler->utf8_normalize_and_fold) (
+          converter,
+          utf8_name,
+          name_size,
+          long_name,
+          &dest_size);
+        if (eno == 0) {
+          returned_size = (ssize_t)dest_size;
+        }
+      } else {
+        eno = EINVAL;
+      }
+    }
+
+    if ( eno != 0 ) {
+      errno         = eno;
+      returned_size = -1;
+    }
+
+    return returned_size;
+  }
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_save (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    uint16_t                        *long_name,
+    const size_t                     long_name_size)
+{
+    ssize_t      returned_size = 0;
+    int          eno           = 0;
+    size_t       name_size     = utf8_name_size;
+    size_t       name_size_tmp = long_name_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
+    int          i;
+    uint16_t     c;
+    unsigned int chars_written;
+
+    name_size_tmp = long_name_size;
+    name_size = msdos_filename_delete_trailing_dots (
+      &utf8_name[0],
+      utf8_name_size);
+    if (name_size > 0) {
+      /*
+       * Finally convert from UTF-8 to UTF-16
+       */
+      eno = (*converter->handler->utf8_to_utf16) (
+          converter,
+          utf8_name,
+          name_size,
+          &long_name[0],
+          &name_size_tmp);
+      if (eno == 0) {
+        if (name_size_tmp <= (MSDOS_NAME_MAX_LNF_LEN * MSDOS_NAME_LFN_BYTES_PER_CHAR))
+          name_size = name_size_tmp;
+        else
+          eno = ENAMETOOLONG;
+      }
+
+      if ( eno == 0 )
+      {
+        /*
+         * Validate the characters and assign them to the UTF-16 file name
+         */
+        for ( i = 0;
+                 name_size
+              && (c = msdos_get_valid_utf16_filename_character ( long_name[i]) );
+              ++i ) {
+          long_name[i]   = c;
+          returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
+          name_size     -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
+        }
+        if ( name_size == UTF16_NULL_SIZE && c == UTF16_NULL ) {
+          long_name[i]   = c;
+          returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
+          name_size     -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
+        }
+        else if ( name_size != 0 )
+          eno = EINVAL;
+        chars_written = returned_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
+        if (   long_name [chars_written - 1] != UTF16_NULL
+            && (returned_size + UTF16_NULL_SIZE ) <= long_name_size ) {
+          long_name[chars_written] = UTF16_NULL;
+        }
+      }
+    }
+    else
+      eno = EINVAL;
+
+    if ( eno != 0 ) {
+      errno         = eno;
+      returned_size = -1;
+    }
+
+    return returned_size;
+  }
+
+/*
+ * Remove any dots from the start of a file name.
+ */
+static void msdos_filename_remove_prepended_dots (const uint8_t **name_utf8,
+                                                  size_t         *name_size)
+{
+  while (    *name_size >= UTF8_FULL_STOP_SIZE
+         && **name_utf8 == UTF8_FULL_STOP) {
+    *name_utf8  += UTF8_FULL_STOP_SIZE;
+    *name_size  -= UTF8_FULL_STOP_SIZE;
+  }
+}
+
+ssize_t
+msdos_filename_utf8_to_short_name_for_compare (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    void                            *short_name,
+    const size_t                     short_name_size)
+{
+  ssize_t        returned_size           = 0;
+  int            eno                     = 0;
+  const uint8_t *name_ptr                = utf8_name;
+  char          *dest_ptr                = (char*)short_name;
+  size_t         name_size               = utf8_name_size;
+  uint8_t        name_normalized_buf[(MSDOS_SHORT_NAME_LEN +1) * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
+  size_t         name_size_tmp           = sizeof(name_normalized_buf);
+
+  returned_size = msdos_filename_process_dot_names (
+    utf8_name,
+    utf8_name_size,
+    short_name,
+    short_name_size);
+
+  if (returned_size == 0) {
+    msdos_filename_remove_prepended_dots (&name_ptr,
+                                          &name_size);
+    if (name_size > 0) {
+      /*
+       * Normalize the name and convert to lower case
+       */
+      eno = (*converter->handler->utf8_normalize_and_fold) (
+        converter,
+        name_ptr,
+        name_size,
+        &name_normalized_buf[0],
+        &name_size_tmp);
+      name_ptr  = &name_normalized_buf[0];
+      name_size = name_size_tmp;
+      if ( eno == ENOMEM ) {
+        eno = 0;
+      }
+      if ( eno == 0 ) {
+        memcpy (&dest_ptr[0], &name_ptr[0], name_size);
+        returned_size = name_size;
+      }
+    } else
+      eno = EINVAL;
+  }
+
+  if ( eno != 0 ) {
+    errno         = eno;
+    returned_size = -1;
+  }
+
+  return returned_size;
+}
+
+ssize_t
+msdos_filename_utf8_to_short_name_for_save (
+    rtems_dosfs_convert_control     *converter,
+    const uint8_t                   *utf8_name,
+    const size_t                     utf8_name_size,
+    void                            *short_name,
+    const size_t                     short_name_size)
+{
+  ssize_t        returned_size           = 0;
+  int            eno                     = 0;
+  const uint8_t *name_ptr                = utf8_name;
+  size_t         name_size               = utf8_name_size;
+  char          *dest_ptr                = (char*)short_name;
+  unsigned int   i;
+  char           c;
+  size_t         name_size_tmp;
+  char           name_to_format_buf[MSDOS_SHORT_NAME_LEN +1];
+
+  returned_size = msdos_filename_process_dot_names (
+    utf8_name,
+    utf8_name_size,
+    short_name,
+    short_name_size);
+
+  if (returned_size == 0) {
+    msdos_filename_remove_prepended_dots (&name_ptr,
+                                          &name_size);
+
+    if (name_size > 0) {
+      /*
+       * Finally convert from UTF-8 to codepage
+       */
+      name_size_tmp = sizeof ( name_to_format_buf );
+      eno = (*converter->handler->utf8_to_codepage) (
+        converter,
+        name_ptr,
+        name_size,
+        &name_to_format_buf[0],
+        &name_size_tmp);
+      if ( eno != 0 ) {
+        /* The UTF-8 name my well be long name, for which we now want to
+         * generate the corresponding short name. Under these circumstances
+         * eno != 0 likely simply means that the UTF-8 name is longer than 11 characters
+         * or that it contains unicode characters which can not be converted to the code page
+         * in a reversible way. Non-reversible characters will be represented by question mark
+         * characters. Later in this method they will get replaced by underline characters.
+         */
+        eno = 0;
+      }
+      name_ptr  = (const uint8_t *)(&name_to_format_buf[0]);
+      name_size = name_size_tmp;
+      for (i = 0; i < name_size; ++i)
+        name_to_format_buf[i] = toupper ( (unsigned char)(name_to_format_buf[i]) );
+      /*
+       * Validate the characters and assign them to the codepage file name
+       */
+      if ( name_size > 0 ) {
+        /*
+         * The first character needs some special treatment
+         */
+        if ( 0x20 == *name_ptr )
+          dest_ptr[0] = '_';
+        else if ( 0xE5 == *name_ptr )
+          dest_ptr[0] = 0x05;
+        else if (0 != (c = msdos_get_valid_codepage_filename_character( *name_ptr ) ) )
+          dest_ptr[0] = c;
+        else
+          dest_ptr[0] = '_';
+        ++name_ptr;
+        ++returned_size;
+        --name_size;
+        /*
+         * Validate and assign all other characters of the name part
+         */
+        for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
+          c = msdos_get_valid_codepage_filename_character ( *name_ptr );
+          if (c != 0)
+            dest_ptr[i] = c;
+          else
+            dest_ptr[i] = '_';
+          ++name_ptr;
+          ++returned_size;
+          --name_size;
+        }
+        /*
+         * Strip any further characters up to a '.' or the end of the
+         * string.
+         */
+        if ( *name_ptr == '.' ) {
+          ++name_ptr;
+          --name_size;
+        }
+
+        for (; i < 8; ++i) {
+          dest_ptr[i] = ' ';
+          ++returned_size;
+        }
+
+        /*
+         * Copy in the extension part of the name, if any.
+         */
+        for (; i <= 10 && name_size ; i++) {
+          c = msdos_get_valid_codepage_filename_character ( *name_ptr);
+          if (c != 0)
+            dest_ptr[i] = c;
+          else
+            dest_ptr[i] = '_';
+          ++name_ptr;
+          ++returned_size;
+          name_size--;
+        }
+        /*
+         * Fill up with blanks. These are DOS's pad characters.
+         */
+        for ( ; i < short_name_size; ++i ) {
+          dest_ptr[i] = ' ';
+          ++returned_size;
+        }
+      }
+    }
+    else
+      eno = EINVAL;
+  }
+
+  if ( eno != 0 ) {
+    errno = eno;
+    return -1;
+  }
+
+  return returned_size;
+}
+
+
Index: cpukit/libfs/src/dosfs/msdos_conv_default.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_conv_default.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
+++ cpukit/libfs/src/dosfs/msdos_conv_default.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -0,0 +1,188 @@
+/**
+ * @file
+ *
+ * @ingroup DOSFS
+ *
+ * @brief Default Converter
+ */
+
+/*
+ * Copyright (c) 2013 embedded brains GmbH.  All rights reserved.
+ *
+ *  embedded brains GmbH
+ *  Dornierstr. 4
+ *  82178 Puchheim
+ *  Germany
+ *  <rtems@embedded-brains.de>
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ */
+
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <assert.h>
+#include <rtems/endian.h>
+#include <rtems/dosfs.h>
+#include "fat.h"
+#include "msdos.h"
+
+static int msdos_default_utf8_to_codepage(
+  rtems_dosfs_convert_control *super,
+  const uint8_t               *src,
+  const size_t                 src_size,
+  char                        *dst,
+  size_t                      *dst_size
+)
+{
+  int    eno = 0;
+  size_t bytes_to_copy = MIN( src_size, *dst_size );
+
+  (void) super;
+
+  *dst_size = bytes_to_copy;
+
+  memcpy( dst, src, bytes_to_copy );
+
+  return eno;
+}
+
+static int msdos_default_codepage_to_utf8(
+  rtems_dosfs_convert_control *super,
+  const char                  *src,
+  const size_t                 src_size,
+  uint8_t                     *dst,
+  size_t                      *dst_size
+)
+{
+  int    eno = 0;
+  size_t bytes_to_copy = MIN( src_size, *dst_size );
+
+  (void) super;
+
+  *dst_size = bytes_to_copy;
+
+  memcpy( dst, src, bytes_to_copy );
+
+  return eno;
+}
+
+static int msdos_default_utf8_to_utf16(
+  rtems_dosfs_convert_control *super,
+  const uint8_t               *src,
+  const size_t                 src_size,
+  uint16_t                    *dst,
+  size_t                      *dst_size
+)
+{
+  int    eno = 0;
+  size_t bytes_to_copy = MIN( src_size, *dst_size / 2);
+  size_t i;
+
+  (void) super;
+
+  *dst_size = 2 * bytes_to_copy;
+
+  for ( i = 0; eno == 0 && i < bytes_to_copy; ++i ) {
+    uint16_t utf16_native = src[i];
+
+    if ( utf16_native <= 127 ) {
+      dst[i] = CT_LE_W( utf16_native );
+    } else {
+      eno = EINVAL;
+    }
+  }
+
+  return eno;
+}
+
+static int msdos_default_utf16_to_utf8(
+  rtems_dosfs_convert_control *super,
+  const uint16_t              *src,
+  const size_t                 src_size,
+  uint8_t                     *dst,
+  size_t                      *dst_size
+)
+{
+  int    eno = 0;
+  size_t bytes_to_copy = MIN( src_size / 2, *dst_size );
+  size_t i;
+
+  (void) super;
+
+  *dst_size = bytes_to_copy;
+
+  for ( i = 0; eno == 0 && i < bytes_to_copy; ++i ) {
+    uint16_t utf16_le = src[i];
+    uint16_t utf16_native  = CF_LE_W( utf16_le );
+
+    if ( utf16_native <= 127 ) {
+      dst[i] = (uint8_t) utf16_native;
+    } else {
+      eno = EINVAL;
+    }
+  }
+
+  return eno;
+}
+
+static int msdos_default_normalize_and_fold(
+  rtems_dosfs_convert_control *super,
+  const uint8_t               *src,
+  const size_t                 src_size,
+  uint8_t                     *dst,
+  size_t                      *dst_size
+)
+{
+  int    eno = 0;
+  size_t bytes_to_copy = MIN( src_size, *dst_size );
+  size_t i;
+
+  (void) super;
+
+  *dst_size = bytes_to_copy;
+
+  for ( i = 0; i < bytes_to_copy; ++i ) {
+    dst[i] = tolower( src[i] );
+  }
+
+  return eno;
+}
+
+static void msdos_default_destroy(
+  rtems_dosfs_convert_control *super
+)
+{
+  free( super );
+}
+
+static const rtems_dosfs_convert_handler msdos_default_convert_handler = {
+  .utf8_to_codepage = msdos_default_utf8_to_codepage,
+  .codepage_to_utf8 = msdos_default_codepage_to_utf8,
+  .utf8_to_utf16 = msdos_default_utf8_to_utf16,
+  .utf16_to_utf8 = msdos_default_utf16_to_utf8,
+  .utf8_normalize_and_fold = msdos_default_normalize_and_fold,
+  .destroy = msdos_default_destroy
+};
+
+typedef struct {
+  rtems_dosfs_convert_control super;
+  uint8_t buffer[MSDOS_NAME_MAX_LFN_BYTES];
+} msdos_default_convert_control;
+
+rtems_dosfs_convert_control *rtems_dosfs_create_default_converter(void)
+{
+  msdos_default_convert_control *self = malloc( sizeof( *self ) );
+
+  if ( self != NULL ) {
+    rtems_dosfs_convert_control *super = &self->super;
+
+    super->handler = &msdos_default_convert_handler;
+    super->buffer.data = &self->buffer;
+    super->buffer.size = sizeof( self->buffer );
+  }
+
+  return &self->super;
+}
Index: cpukit/libfs/src/dosfs/msdos_create.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_create.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_create.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -91,5 +91,6 @@
     }
 
-    name_type = msdos_long_to_short (name, name_len,
+    name_type = msdos_long_to_short (fs_info->converter,
+                                     name, name_len,
                                      MSDOS_DIR_NAME(short_node),
                                      MSDOS_NAME_MAX);
Index: cpukit/libfs/src/dosfs/msdos_dir.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_dir.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_dir.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -9,4 +9,7 @@
  *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
  *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ *  Modifications to support UTF-8 in the file system are
+ *  Copyright (c) 2013 embedded brains GmbH.
  *
  *  The license and distribution terms for this file may be
@@ -34,72 +37,5 @@
 #include "msdos.h"
 
-/*  msdos_format_dirent_with_dot --
- *      This routine convert a (short) MSDOS filename as present on disk
- *      (fixed 8+3 characters, filled with blanks, without separator dot)
- *      to a "normal" format, with between 0 and 8 name chars,
- *      a separating dot and up to 3 extension characters
- *   Rules to work:
- *      - copy any (0-8) "name" part characters that are non-blank
- *      - if an extension exists, append a dot
- *      - copy any (0-3) non-blank extension characters
- *      - append a '\0' (dont count it for the rturn code
- *
- * PARAMETERS:
- *     dst: pointer to destination char array (must be big enough)
- *     src: pointer to source characters
- *
- *
- * RETURNS:
- *     the number of bytes (without trailing '\0'(written to destination
- */
-static ssize_t
-msdos_format_dirent_with_dot(char *dst,const char *src)
-{
-  ssize_t len;
-  int i;
-  const char *src_tmp;
-
-  /*
-   * find last non-blank character of base name
-   */
-  for ((i       =       MSDOS_SHORT_BASE_LEN  ,
-	src_tmp = src + MSDOS_SHORT_BASE_LEN-1);
-       ((i > 0) &&
-	(*src_tmp == ' '));
-       i--,src_tmp--)
-    {};
-  /*
-   * copy base name to destination
-   */
-  src_tmp = src;
-  len = i;
-  while (i-- > 0) {
-    *dst++ = tolower((unsigned char)(*src_tmp++));
-  }
-  /*
-   * find last non-blank character of extension
-   */
-  for ((i       =                            MSDOS_SHORT_EXT_LEN  ,
-	src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1);
-       ((i > 0) &&
-	(*src_tmp == ' '));
-       i--,src_tmp--)
-    {};
-  /*
-   * extension is not empty
-   */
-  if (i > 0) {
-    *dst++ = '.'; /* append dot */
-    len += i + 1; /* extension + dot */
-    src_tmp = src + MSDOS_SHORT_BASE_LEN;
-    while (i-- > 0) {
-      *dst++ = tolower((unsigned char)(*src_tmp++));
-      len++;
-    }
-  }
-  *dst = '\0'; /* terminate string */
-
-  return len;
-}
+
 
 /*  msdos_dir_read --
@@ -129,9 +65,16 @@
 {
     int                rc = RC_OK;
+    int                eno = 0;
     rtems_status_code  sc = RTEMS_SUCCESSFUL;
     msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
+    rtems_dosfs_convert_control *converter = fs_info->converter;
+    const rtems_dosfs_convert_handler *convert_handler = converter->handler;
     fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
     fat_file_fd_t     *tmp_fat_fd = NULL;
     struct dirent      tmp_dirent;
+    size_t             tmp_lfn_len = 0;
+    uint16_t          *lfn_buf = converter->buffer.data;
+    char              *sfn_buf = converter->buffer.data;
+    const size_t       buf_size = converter->buffer.size;
     uint32_t           start = 0;
     ssize_t            ret = 0;
@@ -143,4 +86,6 @@
     uint8_t            lfn_checksum = 0;
     int                lfn_entries = 0;
+    size_t             string_size = sizeof(tmp_dirent.d_name);
+    bool               is_first_entry;
 
     /*
@@ -168,5 +113,5 @@
         rtems_set_errno_and_return_minus_one(EIO);
 
-    while (count > 0)
+    while (count > 0 && cmpltd >= 0)
     {
         /*
@@ -184,5 +129,5 @@
         }
 
-        for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+        for (i = 0; i < ret && cmpltd >= 0; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
         {
             char* entry = (char*) fs_info->cl_buf + i;
@@ -214,7 +159,5 @@
                 MSDOS_ATTR_LFN)
             {
-                int   o;
-                char* p;
-                int   q;
+                int offset_lfn;
 
                 /*
@@ -223,4 +166,5 @@
                 if (lfn_start == FAT_FILE_SHORT_NAME)
                 {
+                    is_first_entry = true;
                     /*
                      * The first entry must have the last long entry flag set.
@@ -242,7 +186,10 @@
                     lfn_entries = (*MSDOS_DIR_ENTRY_TYPE(entry) &
                                    MSDOS_LAST_LONG_ENTRY_MASK);
+                    tmp_lfn_len = 0;
                     lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
                     memset (tmp_dirent.d_name, 0, sizeof(tmp_dirent.d_name));
                 }
+                else
+                    is_first_entry = false;
 
                 /*
@@ -263,5 +210,7 @@
                  * Extract the file name into the directory entry. The data is
                  * stored in UNICODE characters (16bit). No translation is
-                 * currently supported.
+                 * done for the possibly partial entry.
+                 * Once all entries have been assembled to a UTF-16 file name,
+                 * this file name will get converted to UTF-8.
                  *
                  * The DOS maximum length is 255 characters without the
@@ -271,30 +220,11 @@
 
                 lfn_entries--;
-                p = entry + 1;
-                o = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY;
-
-                for (q = 0; q < MSDOS_LFN_LEN_PER_ENTRY; q++)
-                {
-                    if (o >= (sizeof(tmp_dirent.d_name) - 1))
-                        break;
-
-                    tmp_dirent.d_name[o++] = *p;
-
-                    if (*p == '\0')
-                        break;
-
-                    switch (q)
-                    {
-                        case 4:
-                            p += 5;
-                            break;
-                        case 10:
-                            p += 4;
-                            break;
-                        default:
-                            p += 2;
-                            break;
-                    }
-                }
+                offset_lfn = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY;
+                tmp_lfn_len += msdos_get_utf16_string_from_long_entry (
+                  entry,
+                  &lfn_buf[offset_lfn],
+                  buf_size - offset_lfn,
+                  is_first_entry
+                );
             }
             else
@@ -345,7 +275,8 @@
 
                 /*
-                 * If a long file name check if the correct number of
-                 * entries have been found and if the checksum is correct.
-                 * If not return the short file name.
+                 * If a long file name check if the correct number of entries
+                 * have been found and if the checksum is correct and if it is
+                 * convertable to utf8 string.  If not return the short file
+                 * name.
                  */
                 if (lfn_start != FAT_FILE_SHORT_NAME)
@@ -360,4 +291,18 @@
                     if (lfn_entries || (lfn_checksum != cs))
                         lfn_start = FAT_FILE_SHORT_NAME;
+
+                    eno = (*convert_handler->utf16_to_utf8) (
+                        converter,
+                        lfn_buf,
+                        tmp_lfn_len,
+                        (uint8_t*)(&tmp_dirent.d_name[0]),
+                        &string_size);
+                    if (eno == 0) {
+                      tmp_dirent.d_namlen                    = string_size;
+                      tmp_dirent.d_name[tmp_dirent.d_namlen] = '\0';
+                    }
+                    else {
+                        lfn_start = FAT_FILE_SHORT_NAME;
+                    }
                 }
 
@@ -369,23 +314,35 @@
                      */
                     tmp_dirent.d_namlen = msdos_format_dirent_with_dot(
-                        tmp_dirent.d_name, entry); /* src text */
-                }
-                else
-                {
-                    tmp_dirent.d_namlen = strlen(tmp_dirent.d_name);
-                }
-
-                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(&fs_info->fat, tmp_fat_fd);
-                if (rc != RC_OK)
-                {
-                    rtems_semaphore_release(fs_info->vol_sema);
-                    return rc;
+                        sfn_buf, entry); /* src text */
+                    eno = (*convert_handler->codepage_to_utf8) (
+                        converter,
+                        sfn_buf,
+                        tmp_dirent.d_namlen,
+                        (uint8_t*)(&tmp_dirent.d_name[0]),
+                        &string_size);
+                    if ( 0 == eno ) {
+                      tmp_dirent.d_namlen                    = string_size;
+                      tmp_dirent.d_name[tmp_dirent.d_namlen] = '\0';
+                    }
+                    else {
+                        cmpltd = -1;
+                        errno  = eno;
+                    }
+                }
+
+                if ( cmpltd >= 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(&fs_info->fat, tmp_fat_fd);
+                    if (rc != RC_OK)
+                    {
+                        rtems_semaphore_release(fs_info->vol_sema);
+                        return rc;
+                    }
                 }
             }
Index: cpukit/libfs/src/dosfs/msdos_fsunmount.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_fsunmount.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_fsunmount.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -48,6 +48,7 @@
     msdos_fs_info_t *fs_info = temp_mt_entry->fs_info;
     fat_file_fd_t   *fat_fd = temp_mt_entry->mt_fs_root->location.node_access;
+    rtems_dosfs_convert_control *converter = fs_info->converter;
 
-    /* close fat-file which correspondes to root directory */
+    /* close fat-file which corresponds to root directory */
     fat_file_close(&fs_info->fat, fat_fd);
 
@@ -55,4 +56,5 @@
 
     rtems_semaphore_delete(fs_info->vol_sema);
+    (*converter->handler->destroy)( converter );
     free(fs_info->cl_buf);
     free(temp_mt_entry->fs_info);
Index: cpukit/libfs/src/dosfs/msdos_init.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_init.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_init.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -12,4 +12,7 @@
  *  Modifications to support reference counting in the file system are
  *  Copyright (c) 2012 embedded brains GmbH.
+ *
+ *  Modifications to support UTF-8 in the file system are
+ *  Copyright (c) 2013 embedded brains GmbH.
  *
  *  The license and distribution terms for this file may be
@@ -90,13 +93,31 @@
  *
  */
-int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
-                           const void                           *data)
+int rtems_dosfs_initialize(
+  rtems_filesystem_mount_table_entry_t *mt_entry,
+  const void                           *data
+)
 {
-    int rc;
+    int                                rc = 0;
+    const rtems_dosfs_mount_options   *mount_options = data;
+    rtems_dosfs_convert_control       *converter;
 
-    rc = msdos_initialize_support(mt_entry,
-                                  &msdos_ops,
-                                  &msdos_file_handlers,
-                                  &msdos_dir_handlers);
+
+    if (mount_options == NULL || mount_options->converter == NULL) {
+        converter = rtems_dosfs_create_default_converter();
+    } else {
+        converter = mount_options->converter;
+    }
+
+    if (converter != NULL) {
+        rc = msdos_initialize_support(mt_entry,
+                                      &msdos_ops,
+                                      &msdos_file_handlers,
+                                      &msdos_dir_handlers,
+                                      converter);
+    } else {
+        errno = ENOMEM;
+        rc = -1;
+    }
+
     return rc;
 }
Index: cpukit/libfs/src/dosfs/msdos_initsupp.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_initsupp.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_initsupp.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -53,5 +53,6 @@
     const rtems_filesystem_operations_table *op_table,
     const rtems_filesystem_file_handlers_r  *file_handlers,
-    const rtems_filesystem_file_handlers_r  *directory_handlers
+    const rtems_filesystem_file_handlers_r  *directory_handlers,
+    rtems_dosfs_convert_control             *converter
     )
 {
@@ -68,4 +69,6 @@
 
     temp_mt_entry->fs_info = fs_info;
+
+    fs_info->converter = converter;
 
     rc = fat_init_volume_info(&fs_info->fat, temp_mt_entry->dev);
Index: cpukit/libfs/src/dosfs/msdos_misc.c
===================================================================
--- cpukit/libfs/src/dosfs/msdos_misc.c	(revision 8bed60314e383fe461c03236857b9ba369beecd4)
+++ cpukit/libfs/src/dosfs/msdos_misc.c	(revision d2e0bb36e34f1fe45641f26b8b8d6ef615963854)
@@ -9,4 +9,7 @@
  *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
  *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
+ *
+ *  Modifications to support UTF-8 in the file system are
+ *  Copyright (c) 2013 embedded brains GmbH.
  *
  *  The license and distribution terms for this file may be
@@ -27,4 +30,6 @@
 #include <string.h>
 #include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
 #include <rtems/libio_.h>
 
@@ -70,5 +75,5 @@
 
     if ((ch == '.') || isalnum((unsigned char)ch) ||
-        (strchr("$%'-_@~`!(){}^#&", ch) != NULL))
+        (strchr("$%'-_@~`!(){}^#&", ch) != NULL) || (unsigned char) ch > 127)
         return MSDOS_NAME_SHORT;
 
@@ -193,8 +198,16 @@
 #define MSDOS_L2S_PRINT 0
 msdos_name_type_t
-msdos_long_to_short(const char *lfn, int lfn_len, char* sfn, int sfn_len)
+msdos_long_to_short(rtems_dosfs_convert_control     *converter,
+                    const char                      *lfn,
+                    int                              lfn_len,
+                    char                            *sfn,
+                    int                              sfn_len)
 {
     msdos_name_type_t type;
+    int               eno = 0;
     int               i;
+    ssize_t           short_filename_length = sfn_len;
+    void             *buffer = converter->buffer.data;
+    size_t            codepage_name_len = converter->buffer.size;
 
     /*
@@ -243,19 +256,44 @@
      */
 
-    type = msdos_name_type (lfn, lfn_len);
-
-    if (type == MSDOS_NAME_INVALID)
+    eno = (*converter->handler->utf8_to_codepage) (
+        converter,
+        (const uint8_t*)&lfn[0],
+        lfn_len,
+        buffer,
+        &codepage_name_len);
+    if (eno == EINVAL)
+    {
+        eno = 0;
+        type = MSDOS_NAME_LONG;
+    }
+    else
+    {
+        type = msdos_name_type (
+            buffer,
+            codepage_name_len);
+    }
+
+    if (type != MSDOS_NAME_INVALID)
+    {
+        short_filename_length = msdos_filename_utf8_to_short_name_for_save (
+            converter,
+            (const uint8_t*)lfn,
+            lfn_len,
+            sfn,
+            short_filename_length);
+        if (short_filename_length < 0 ) {
+            type = MSDOS_NAME_INVALID;
+        }
+#if MSDOS_L2S_PRINT
+        printf ("MSDOS_L2S: TYPE:%d lfn:'%s' SFN:'%s'\n", type, lfn, sfn);
+#endif
+    }
+    else
     {
 #if MSDOS_L2S_PRINT
         printf ("MSDOS_L2S: INVALID[2]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
 #endif
-        return MSDOS_NAME_INVALID;
-    }
-
-    msdos_filename_unix2dos (lfn, lfn_len, sfn);
-
-#if MSDOS_L2S_PRINT
-    printf ("MSDOS_L2S: TYPE:%d lfn:'%s' SFN:'%s'\n", type, lfn, sfn);
-#endif
+    }
+
     return type;
 }
@@ -293,11 +331,13 @@
     memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
 
-    name_type = msdos_long_to_short (name,
-                                     name_len,
-                                     MSDOS_DIR_NAME(node_entry),
-                                     MSDOS_NAME_MAX);
+    name_type = msdos_long_to_short (
+        fs_info->converter,
+        name,
+        name_len,
+        MSDOS_DIR_NAME(node_entry),
+        MSDOS_NAME_MAX);
 
     /*
-     * find the node which correspondes to the name in the directory pointed by
+     * find the node which corresponds to the name in the directory pointed by
      * 'parent_loc'
      */
@@ -427,5 +467,5 @@
     /* find name in fat-file which corresponds to the directory */
     rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd,
-                                     create_node, name, name_len, name_type,
+                                     create_node, (const uint8_t*)name, name_len, name_type,
                                      dir_pos, name_dir_entry);
     if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
@@ -519,4 +559,5 @@
     char             dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
     uint32_t         cl4find = 0;
+    rtems_dosfs_convert_control *converter = fs_info->converter;
 
     /*
@@ -543,6 +584,8 @@
     /* find "." node in opened directory */
     memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
-    msdos_long_to_short(".", 1, dot_node, MSDOS_SHORT_NAME_LEN);
-    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, ".", 1,
+    msdos_long_to_short(
+        converter,
+        ".", 1, dot_node, MSDOS_SHORT_NAME_LEN);
+    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)".", 1,
                                      MSDOS_NAME_SHORT, dir_pos, dot_node);
 
@@ -555,6 +598,8 @@
     /* find ".." node in opened directory */
     memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
-    msdos_long_to_short("..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN);
-    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, "..", 2,
+    msdos_long_to_short(
+        converter,
+        "..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN);
+    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)"..", 2,
                                      MSDOS_NAME_SHORT, dir_pos,
                                      dotdot_node);
@@ -915,88 +960,314 @@
 }
 
-/* msdos_create_name_in_fat_file --
- *     This routine creates an entry in the fat file for the file name
- *     provided by the user. The directory entry passed is the short
- *     file name and is added as it. If the file name is long a long
- *     file name set of entries is added.
- *
- *     Scan the directory for the file and if not found add the new entry.
- *     When scanning remember the offset in the file where the directory
- *     entry can be added.
+#define MSDOS_FIND_PRINT 0
+static int
+msdos_on_entry_found (
+    msdos_fs_info_t                      *fs_info,
+    fat_file_fd_t                        *fat_fd,
+    const uint32_t                        bts2rd,
+    char                                 *name_dir_entry,
+    char                                 *entry,
+    fat_dir_pos_t                        *dir_pos,
+    uint32_t                             *dir_offset,
+    const uint32_t                        dir_entry,
+    const fat_pos_t                      *lfn_start
+)
+{
+    int rc = RC_OK;
+#if MSDOS_FIND_PRINT
+    printf ("MSFS:[9.3] SNF found\n");
+#endif
+    /*
+     * We get the entry we looked for - fill the position
+     * structure and the 32 bytes of the short entry
+     */
+    rc = fat_file_ioctl(&fs_info->fat,
+                        fat_fd,
+                        F_CLU_NUM,
+                        *dir_offset * bts2rd,
+                        &dir_pos->sname.cln);
+    if (rc == RC_OK) {
+        dir_pos->sname.ofs = dir_entry;
+
+        if (lfn_start->cln != FAT_FILE_SHORT_NAME)
+        {
+            rc = fat_file_ioctl (&fs_info->fat,
+                                 fat_fd,
+                                 F_CLU_NUM,
+                                 lfn_start->cln * bts2rd,
+                                 &lfn_start->cln);
+        }
+        if ( rc == RC_OK ) {
+            dir_pos->lname.cln = lfn_start->cln;
+            dir_pos->lname.ofs = lfn_start->ofs;
+
+            memcpy(name_dir_entry, entry,
+                   MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+        }
+    }
+
+    return rc;
+}
+
+ssize_t
+msdos_get_utf16_string_from_long_entry (
+    const char                 *entry,
+    uint16_t                   *entry_string_buf,
+    const size_t                buf_size,
+    bool                        is_first_entry
+)
+{
+    ssize_t chars_in_entry;
+
+    if (buf_size >= MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR) {
+        memcpy (&entry_string_buf[0],  &entry[1],  10 );
+        memcpy (&entry_string_buf[5],  &entry[14], 12 );
+        memcpy (&entry_string_buf[11], &entry[28],  4 );
+
+        if (is_first_entry) {
+            for (chars_in_entry = 0;
+                 (    entry_string_buf[chars_in_entry] != 0x0000
+                  && chars_in_entry < MSDOS_LFN_LEN_PER_ENTRY );
+                  ++chars_in_entry) {
+                ;
+            }
+        }
+        else
+            chars_in_entry = MSDOS_LFN_LEN_PER_ENTRY;
+
+        return chars_in_entry * MSDOS_NAME_LFN_BYTES_PER_CHAR;
+    }
+    else
+        return ENOMEM;
+}
+
+/*  msdos_format_dirent_with_dot --
+ *      This routine convert a (short) MSDOS filename as present on disk
+ *      (fixed 8+3 characters, filled with blanks, without separator dot)
+ *      to a "normal" format, with between 0 and 8 name chars,
+ *      a separating dot and up to 3 extension characters
+ *   Rules to work:
+ *      - copy any (0-8) "name" part characters that are non-blank
+ *      - if an extension exists, append a dot
+ *      - copy any (0-3) non-blank extension characters
+ *      - append a '\0' (dont count it for the rturn code
  *
  * 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
+ *     dst: pointer to destination char array (must be big enough)
+ *     src: pointer to source characters
+ *
  *
  * RETURNS:
- *     RC_OK on success, or error code if error occured (errno set
- *     appropriately)
- *
+ *     the number of bytes (without trailing '\0'(written to destination
  */
-#define MSDOS_FIND_PRINT 0
-int msdos_find_name_in_fat_file(
-    rtems_filesystem_mount_table_entry_t *mt_entry,
+ssize_t
+msdos_format_dirent_with_dot(char *dst,const char *src)
+{
+  ssize_t len;
+  int i;
+  const char *src_tmp;
+
+  /*
+   * find last non-blank character of base name
+   */
+  for (i = MSDOS_SHORT_BASE_LEN, src_tmp = src + MSDOS_SHORT_BASE_LEN - 1;
+       i > 0 && *src_tmp == ' ';
+       --i,--src_tmp)
+    {};
+  /*
+   * copy base name to destination
+   */
+  src_tmp = src;
+  len = i;
+  while (i-- > 0) {
+    *dst++ = tolower((unsigned char)(*src_tmp++));
+  }
+  /*
+   * find last non-blank character of extension
+   */
+  for (i = MSDOS_SHORT_EXT_LEN,
+        src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1;
+       i > 0 && *src_tmp == ' ';
+       --i, --src_tmp)
+    {};
+  /*
+   * extension is not empty
+   */
+  if (i > 0) {
+    *dst++ = '.'; /* append dot */
+    ++len;        /* dot */
+    src_tmp = src + MSDOS_SHORT_BASE_LEN;
+    while (i-- > 0) {
+      *dst++ = tolower((unsigned char)(*src_tmp++));
+      ++len;
+    }
+  }
+  *dst = '\0'; /* terminate string */
+
+  return len;
+}
+
+static ssize_t
+msdos_long_entry_to_utf8_name (
+    rtems_dosfs_convert_control *converter,
+    const char                  *entry,
+    const bool                   is_first_entry,
+    uint8_t                     *entry_utf8_buf,
+    const size_t                 buf_size)
+{
+    ssize_t      retval         = 0;
+    int          eno            = 0;
+    size_t       bytes_in_utf8  = buf_size;
+    size_t       bytes_in_buf;
+    uint16_t     entry_string[MSDOS_LFN_LEN_PER_ENTRY];
+
+    retval = msdos_get_utf16_string_from_long_entry (
+        entry,
+        entry_string,
+        sizeof (entry_string),
+        is_first_entry
+    );
+
+    if (retval >= 0) {
+        bytes_in_buf = retval;
+        eno = (*converter->handler->utf16_to_utf8) (
+            converter,
+            &entry_string[0],
+            bytes_in_buf,
+            &entry_utf8_buf[0],
+            &bytes_in_utf8);
+        if ( eno == 0 ) {
+            retval = bytes_in_utf8;
+        }
+    }
+
+    if (eno != 0) {
+        retval = -1;
+        errno  = eno;
+    }
+
+    return retval;
+}
+
+static ssize_t msdos_short_entry_to_utf8_name (
+  rtems_dosfs_convert_control     *converter,
+  const char                      *entry,
+  uint8_t                         *buf,
+  const size_t                     buf_size)
+{
+  char         char_buf[MSDOS_NAME_MAX_WITH_DOT];
+  int          eno             = 0;
+  size_t       bytes_converted = buf_size;
+  ssize_t      bytes_written   = msdos_format_dirent_with_dot(char_buf, entry);
+
+  if (bytes_written > 0) {
+    if (char_buf[0] == 0x05)
+      char_buf[0] = 0xE5;
+
+    eno = (*converter->handler->codepage_to_utf8) (
+        converter,
+        char_buf,
+        bytes_written,
+        buf,
+        &bytes_converted);
+    if (eno == 0)
+        bytes_written = bytes_converted;
+  } else {
+      eno = EINVAL;
+  }
+
+  if (eno != 0) {
+      bytes_written = -1;
+      errno         = eno;
+  }
+
+  return bytes_written;
+}
+
+static ssize_t
+msdos_compare_entry_against_filename (
+    rtems_dosfs_convert_control *converter,
+    const uint8_t               *entry,
+    const size_t                 entry_size,
+    const uint8_t               *filename,
+    const size_t                 filename_size_remaining,
+    bool                        *is_matching)
+{
+  ssize_t      size_remaining = filename_size_remaining;
+  int          eno            = 0;
+  uint8_t      entry_normalized[( MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_LFN_BYTES_PER_CHAR * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
+  size_t       bytes_in_entry_normalized = sizeof ( entry_normalized );
+
+  eno = (*converter->handler->utf8_normalize_and_fold) (
+      converter,
+      &entry[0],
+      entry_size,
+      &entry_normalized[0],
+      &bytes_in_entry_normalized);
+  if (eno == 0) {
+#if MSDOS_FIND_PRINT > 1
+        printf ( "MSFS:[6] entry_normalized:%s"
+                 "name:%s\n",
+                 entry,
+                 filename );
+#endif
+        if (bytes_in_entry_normalized <= size_remaining) {
+            size_remaining = size_remaining - bytes_in_entry_normalized;
+            if (0 == memcmp ( &entry_normalized[0],
+                              &filename[size_remaining],
+                              bytes_in_entry_normalized)) {
+                *is_matching = true;
+            } else {
+                *is_matching   = false;
+                size_remaining = filename_size_remaining;
+            }
+
+        }
+        else {
+          *is_matching = false;
+        }
+    }
+
+    if (eno != 0) {
+      size_remaining = -1;
+      errno          = eno;
+    }
+
+    return size_remaining;
+}
+
+static int
+msdos_find_file_in_directory (
+    const uint8_t                        *filename_converted,
+    const size_t                          name_len_for_compare,
+    const size_t                          name_len_for_save,
+    const msdos_name_type_t               name_type,
+    msdos_fs_info_t                      *fs_info,
     fat_file_fd_t                        *fat_fd,
-    bool                                  create_node,
-    const char                           *name,
-    int                                   name_len,
-    msdos_name_type_t                     name_type,
+    const uint32_t                        bts2rd,
+    const bool                            create_node,
+    const unsigned int                    fat_entries,
+    char                                 *name_dir_entry,
     fat_dir_pos_t                        *dir_pos,
-    char                                 *name_dir_entry
-                                )
-{
-    ssize_t          ret = 0;
-    msdos_fs_info_t *fs_info = mt_entry->fs_info;
-    uint32_t         dir_offset = 0;
-    uint32_t         dir_entry = 0;
-    uint32_t         bts2rd = 0;
-    fat_pos_t        lfn_start;
-    bool             lfn_matched = false;
-    uint8_t          lfn_checksum = 0;
-    int              lfn_entries;
-    int              lfn_entry = 0;
-    uint32_t         empty_space_offset = 0;
-    uint32_t         empty_space_entry = 0;
-    uint32_t         empty_space_count = 0;
-    bool             empty_space_found = false;
-    uint32_t         entries_per_block;
-    bool             read_cluster = false;
-
-    assert(name_len > 0);
-
-    fat_dir_pos_init(dir_pos);
-
-    lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
-
-    /*
-     * Set the number of short entries needed to store the LFN. If the name
-     * is short still check for possible long entries with the short name.
-     *
-     * In PR1491 we need to have a LFN for a short file name entry. To
-     * test this make this test always fail, ie add "0 &&".
-     */
-    if (create_node && (name_type == MSDOS_NAME_SHORT))
-      lfn_entries = 0;
-    else
-      lfn_entries =
-        ((name_len - 1) + MSDOS_LFN_LEN_PER_ENTRY) / MSDOS_LFN_LEN_PER_ENTRY;
-
-    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;
-
-    entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
-
-#if MSDOS_FIND_PRINT
-    printf ("MSFS:[1] nt:%d, cn:%i ebp:%li bts2rd:%li lfne:%d nl:%i n:%s\n",
-            name_type, create_node, entries_per_block, bts2rd,
-            lfn_entries, name_len, name);
-#endif
+    uint32_t                             *dir_offset,
+    uint32_t                             *empty_space_offset,
+    uint32_t                             *empty_space_entry,
+    uint32_t                             *empty_space_count)
+{
+    int               rc                = RC_OK;
+    ssize_t           bytes_read;
+    uint32_t          dir_entry;
+    fat_pos_t         lfn_start;
+    uint8_t           lfn_checksum      = 0;
+    bool              entry_matched       = false;
+    bool              empty_space_found = false;
+    uint32_t          entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
+    int               lfn_entry         = 0;
+    uint8_t           entry_utf8_normalized[(MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_LFN_BYTES_PER_CHAR * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR/*MSDOS_ENTRY_LFN_UTF8_BYTES*/];
+    size_t            bytes_in_entry;
+    bool              filename_matched  = false;
+    ssize_t           filename_size_remaining = name_len_for_compare;
+    rtems_dosfs_convert_control *converter = fs_info->converter;
+
     /*
      * Scan the directory seeing if the file is present. While
@@ -1004,20 +1275,24 @@
      * create the entry if the name is not found.
      */
-    while ((ret = fat_file_read(&fs_info->fat, fat_fd, (dir_offset * bts2rd),
-                                bts2rd, fs_info->cl_buf)) != FAT_EOF)
+
+    lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
+
+    while (   (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (*dir_offset * bts2rd),
+                                             bts2rd, fs_info->cl_buf)) != FAT_EOF
+           && rc == RC_OK)
     {
         bool remainder_empty = false;
 #if MSDOS_FIND_PRINT
-        printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
-#endif
-
-        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+        printf ("MSFS:[2] dir_offset:%li\n", *dir_offset);
+#endif
+
+        if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
             rtems_set_errno_and_return_minus_one(EIO);
 
-        assert(ret == bts2rd);
+        assert(bytes_read == bts2rd);
 
         /* have to look at the DIR_NAME as "raw" 8-bit data */
         for (dir_entry = 0;
-             dir_entry < bts2rd;
+             dir_entry < bts2rd && rc == RC_OK && (! filename_matched);
              dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
         {
@@ -1026,5 +1301,5 @@
             /*
              * See if the entry is empty or the remainder of the directory is
-             * empty ? Localise to make the code read better.
+             * empty ? Localize to make the code read better.
              */
             bool entry_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
@@ -1034,5 +1309,5 @@
 #if MSDOS_FIND_PRINT
             printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
-                    remainder_empty, entry_empty, dir_offset,
+                    remainder_empty, entry_empty, *dir_offset,
                     dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
 #endif
@@ -1044,8 +1319,8 @@
              * is a count of empty entries.
              */
-            if (empty_space_count == 0)
+            if (*empty_space_count == 0)
             {
-                empty_space_entry = dir_entry;
-                empty_space_offset = dir_offset;
+                *empty_space_entry = dir_entry;
+                *empty_space_offset = *dir_offset;
             }
 
@@ -1060,5 +1335,5 @@
                  */
                 if (!create_node)
-                    return MSDOS_NAME_NOT_FOUND_ERR;
+                    rc = MSDOS_NAME_NOT_FOUND_ERR;
 
                 /*
@@ -1068,11 +1343,12 @@
                  * are needed FAT_EOF is returned by the read and we extend the file.
                  */
-                if (!empty_space_found)
+                if (   !empty_space_found
+                    && rc == RC_OK )
                 {
-                  empty_space_count +=
+                    *empty_space_count +=
                     entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
-                  empty_space_found = true;
-#if MSDOS_FIND_PRINT
-                  printf ("MSFS:[3.2] esf:%i esc%i\n", empty_space_found, empty_space_count);
+                    empty_space_found = true;
+#if MSDOS_FIND_PRINT
+                    printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_space_count );
 #endif
                 }
@@ -1083,15 +1359,15 @@
                 if (create_node)
                 {
-                  /*
-                   * Remainder is not empty so is this entry empty ?
-                   */
-                  empty_space_count++;
-
-                  if (empty_space_count == (lfn_entries + 1))
-                    empty_space_found = true;
+                    /*
+                     * Remainder is not empty so is this entry empty ?
+                     */
+                    (*empty_space_count)++;
+
+                    if (*empty_space_count == (fat_entries + 1))
+                        empty_space_found = true;
                 }
 #if MSDOS_FIND_PRINT
                 printf ("MSFS:[4.1] esc:%li esf:%i\n",
-                        empty_space_count, empty_space_found);
+                        *empty_space_count, empty_space_found);
 #endif
             }
@@ -1106,6 +1382,6 @@
                 if (create_node && !empty_space_found)
                 {
-                    empty_space_entry = 0;
-                    empty_space_count = 0;
+                    *empty_space_entry = 0;
+                    *empty_space_count = 0;
                 }
 
@@ -1117,7 +1393,5 @@
                     MSDOS_ATTR_LFN)
                 {
-                    char* p;
-                    int   o;
-                    int   i;
+/*                    int   o;*/
 #if MSDOS_FIND_PRINT
                     printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
@@ -1132,5 +1406,5 @@
                     if (lfn_start.cln == FAT_FILE_SHORT_NAME)
                     {
-                        lfn_matched = false;
+                        entry_matched = false;
 
                         /*
@@ -1149,5 +1423,5 @@
                          * on when the characters are checked.
                          */
-                        if (lfn_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) &
+                        if (fat_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) &
                                             MSDOS_LAST_LONG_ENTRY_MASK))
                             continue;
@@ -1156,12 +1430,12 @@
                          * Get the checksum of the short entry.
                          */
-                        lfn_start.cln = dir_offset;
+                        lfn_start.cln = *dir_offset;
                         lfn_start.ofs = dir_entry;
-                        lfn_entry = lfn_entries;
+                        lfn_entry = fat_entries;
                         lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
 
 #if MSDOS_FIND_PRINT
                         printf ("MSFS:[4.3] lfn_checksum:%i\n",
-                                *MSDOS_DIR_LFN_CHECKSUM(entry));
+                                lfn_checksum);
 #endif
                     }
@@ -1183,62 +1457,38 @@
                         continue;
                     }
-
+#if MSDOS_FIND_PRINT
+                    printf ("MSFS:[5] lfne:%i\n", lfn_entry);
+#endif
                     lfn_entry--;
-                    o = lfn_entry * MSDOS_LFN_LEN_PER_ENTRY;
-                    p = entry + 1;
-
-#if MSDOS_FIND_PRINT
-                    printf ("MSFS:[5] lfne:%i\n", lfn_entry);
-#endif
-                    for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++)
-                    {
-#if MSDOS_FIND_PRINT > 1
-                        printf ("MSFS:[6] o:%i i:%i *p:%c(%02x) name[o + i]:%c(%02x)\n",
-                                o, i, *p, *p, name[o + i], name[o + i]);
-#endif
-                        if (*p == '\0')
-                        {
-                            /*
-                             * If this is the first entry, ie the last part of the
-                             * long file name and the length does not match then
-                             * the file names do not match.
-                             */
-                            if (((lfn_entry + 1) == lfn_entries) &&
-                                ((o + i) != name_len))
-                                lfn_start.cln = FAT_FILE_SHORT_NAME;
-                            break;
+
+                    bytes_in_entry = msdos_long_entry_to_utf8_name (
+                        converter,
+                        entry,
+                        (lfn_entry + 1) == fat_entries,
+                        &entry_utf8_normalized[0],
+                        sizeof (entry_utf8_normalized));
+                    if (bytes_in_entry > 0) {
+                        filename_size_remaining = msdos_compare_entry_against_filename (
+                            converter,
+                            &entry_utf8_normalized[0],
+                            bytes_in_entry,
+                            &filename_converted[0],
+                            filename_size_remaining,
+                            &entry_matched);
+
+                        if (filename_size_remaining < 0
+                            || (! entry_matched)) {
+                            filename_size_remaining = name_len_for_compare;
+                            lfn_start.cln = FAT_FILE_SHORT_NAME;
                         }
-
-                        if (((o + i) >= name_len) || (*p != name[o + i]))
-                        {
-                            lfn_start.cln = FAT_FILE_SHORT_NAME;
-                            break;
-                        }
-
-                        switch (i)
-                        {
-                            case 4:
-                                p += 5;
-                                break;
-                            case 10:
-                                p += 4;
-                                break;
-                            default:
-                                p += 2;
-                                break;
-                        }
+                    } else {
+                      lfn_start.cln = FAT_FILE_SHORT_NAME;
+                      entry_matched   = false;
                     }
-
-                    lfn_matched = ((lfn_entry == 0) &&
-                                   (lfn_start.cln != FAT_FILE_SHORT_NAME));
-
-#if MSDOS_FIND_PRINT
-                    printf ("MSFS:[8.1] lfn_matched:%i\n", lfn_matched);
-#endif
                 }
                 else
                 {
 #if MSDOS_FIND_PRINT
-                    printf ("MSFS:[9.1] SFN entry, lfn_matched:%i\n", lfn_matched);
+                    printf ("MSFS:[9.1] SFN entry, entry_matched:%i\n", entry_matched);
 #endif
                     /*
@@ -1250,5 +1500,5 @@
                      * name entry.
                      */
-                    if (lfn_matched)
+                    if (entry_matched)
                     {
                         uint8_t  cs = 0;
@@ -1260,79 +1510,115 @@
 
                         if (lfn_entry || (lfn_checksum != cs))
-                            lfn_matched = false;
-#if MSDOS_FIND_PRINT
-                        printf ("MSFS:[9.2] checksum, lfn_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
-                                lfn_matched, lfn_entry, lfn_checksum, cs);
-#endif
+                            entry_matched = false;
+                        else {
+                            filename_matched = true;
+                            rc = msdos_on_entry_found (
+                                fs_info,
+                                fat_fd,
+                                bts2rd,
+                                name_dir_entry,
+                                entry,
+                                dir_pos,
+                                dir_offset,
+                                dir_entry,
+                                &lfn_start
+                            );
+                        }
+
+#if MSDOS_FIND_PRINT
+                        printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
+                                entry_matched, lfn_entry, lfn_checksum, cs);
+#endif
+                    } else {
+                        bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
+                        bytes_in_entry = msdos_short_entry_to_utf8_name (
+                            converter,
+                            MSDOS_DIR_NAME (entry),
+                            &entry_utf8_normalized[0],
+                            bytes_in_entry);
+                        if (bytes_in_entry > 0) {
+                            filename_size_remaining = msdos_compare_entry_against_filename (
+                                converter,
+                                &entry_utf8_normalized[0],
+                                bytes_in_entry,
+                                &filename_converted[0],
+                                name_len_for_compare,
+                                &entry_matched);
+                            if (entry_matched && filename_size_remaining == 0) {
+                                filename_matched = true;
+                                rc = msdos_on_entry_found (
+                                    fs_info,
+                                    fat_fd,
+                                    bts2rd,
+                                    name_dir_entry,
+                                    entry,
+                                    dir_pos,
+                                    dir_offset,
+                                    dir_entry,
+                                    &lfn_start
+                                );
+                            }
+                            if (rc == RC_OK && (! filename_matched)) {
+                                lfn_start.cln           = FAT_FILE_SHORT_NAME;
+                                entry_matched           = false;
+                                filename_size_remaining = name_len_for_compare;
+                            }
+                        } else {
+                          lfn_start.cln           = FAT_FILE_SHORT_NAME;
+                          entry_matched           = false;
+                          filename_size_remaining = name_len_for_compare;
+                        }
                     }
-
-                    /*
-                     * If the long file names matched or the file name is
-                     * short and they match then we have the entry. We will not
-                     * match a long file name against a short file name because
-                     * a long file name that generates a matching short file
-                     * name is not a long file name.
-                     */
-                    if (lfn_matched ||
-                        ((name_type == MSDOS_NAME_SHORT) &&
-                         (lfn_start.cln == FAT_FILE_SHORT_NAME) &&
-                         (memcmp(MSDOS_DIR_NAME(entry),
-                                 MSDOS_DIR_NAME(name_dir_entry),
-                                 MSDOS_SHORT_NAME_LEN) == 0)))
-                    {
-#if MSDOS_FIND_PRINT
-                        printf ("MSFS:[9.3] SNF found\n");
-#endif
-                        /*
-                         * We get the entry we looked for - fill the position
-                         * structure and the 32 bytes of the short entry
-                         */
-                        int rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
-                                                dir_offset * bts2rd,
-                                                &dir_pos->sname.cln);
-                        if (rc != RC_OK)
-                            return rc;
-
-                        dir_pos->sname.ofs = dir_entry;
-
-                        if (lfn_start.cln != FAT_FILE_SHORT_NAME)
-                        {
-                          rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
-                                              lfn_start.cln * bts2rd,
-                                              &lfn_start.cln);
-                          if (rc != RC_OK)
-                            return rc;
-                        }
-
-                        dir_pos->lname.cln = lfn_start.cln;
-                        dir_pos->lname.ofs = lfn_start.ofs;
-
-                        memcpy(name_dir_entry, entry,
-                               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
-                        return RC_OK;
-                    }
-
-                    lfn_start.cln = FAT_FILE_SHORT_NAME;
-                    lfn_matched = false;
                 }
             }
         }
 
-        if (remainder_empty)
+        if (filename_matched || remainder_empty)
             break;
 
-        dir_offset++;
-    }
-
-    /*
-     * If we are not to create the entry return a not found error.
-     */
-    if (!create_node)
-      return MSDOS_NAME_NOT_FOUND_ERR;
-
-#if MSDOS_FIND_PRINT
-    printf ("MSFS:[8.1] WRITE do:%ld esc:%ld eso:%ld ese:%ld\n",
-            dir_offset, empty_space_count, empty_space_offset, empty_space_entry);
-#endif
+        (*dir_offset)++;
+    }
+    if ( ! filename_matched ) {
+        /*
+         * If we are not to create the entry return a not found error.
+         */
+        if (!create_node)
+            rc = MSDOS_NAME_NOT_FOUND_ERR;
+
+#if MSDOS_FIND_PRINT
+        printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" eso:%"PRIu32" ese:%"PRIu32"\n",
+                 *dir_offset, *empty_space_count, *empty_space_offset, *empty_space_entry );
+#endif
+    }
+
+    return rc;
+}
+
+static int
+msdos_add_file (
+    const char                           *name_converted,
+    const msdos_name_type_t               name_type,
+    msdos_fs_info_t                      *fs_info,
+    fat_file_fd_t                        *fat_fd,
+    const uint32_t                        bts2rd,
+    const unsigned int                    fat_entries,
+    const char                           *name_dir_entry,
+    fat_dir_pos_t                        *dir_pos,
+    const uint32_t                        dir_offset,
+    const uint32_t                        empty_space_offset_param,
+    const uint32_t                        empty_space_entry_param,
+    const uint32_t                        empty_space_count
+
+)
+{
+    int              ret                = 0;
+    ssize_t          bytes_written      = 0;
+    uint8_t          lfn_checksum       = 0;
+    uint32_t         empty_space_offset = empty_space_offset_param;
+    uint32_t         empty_space_entry  = empty_space_entry_param;
+    bool             read_cluster       = false;
+    int              lfn_entry          = 0;
+    fat_pos_t        lfn_start;
+    uint32_t         dir_entry;
 
     /*
@@ -1342,13 +1628,12 @@
      * in this directory.
      */
-    lfn_checksum = 0;
     if (name_type == MSDOS_NAME_LONG)
     {
         int      slot = (((empty_space_offset * bts2rd) + empty_space_entry) /
-                         MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1;
+                        MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + fat_entries + 1;
         msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
     }
 
-    if (lfn_entries)
+    if (fat_entries)
     {
         uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(name_dir_entry);
@@ -1393,5 +1678,5 @@
      * The one more is the short entry.
      */
-    while (lfn_entry < (lfn_entries + 1))
+    while (lfn_entry < (fat_entries + 1))
     {
         int length = 0;
@@ -1399,45 +1684,45 @@
         if (read_cluster)
         {
-          uint32_t new_length;
-#if MSDOS_FIND_PRINT
-          printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
-#endif
-          ret = fat_file_read(&fs_info->fat, fat_fd,
-                              (empty_space_offset * bts2rd), bts2rd,
-                              fs_info->cl_buf);
-
-          if (ret != bts2rd)
-          {
-            if (ret != FAT_EOF)
-              rtems_set_errno_and_return_minus_one(EIO);
-
-#if MSDOS_FIND_PRINT
-            printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
-#endif
-            ret = fat_file_extend (&fs_info->fat, fat_fd, false,
-                                   empty_space_offset * bts2rd, &new_length);
-
-            if (ret != RC_OK)
-              return ret;
-
-#if MSDOS_FIND_PRINT
-            printf ("MSFS:[9.3] extended: %d <-> %d\n", new_length, empty_space_offset * bts2rd);
-#endif
-            if (new_length != (empty_space_offset * bts2rd))
-              rtems_set_errno_and_return_minus_one(EIO);
-
-            memset(fs_info->cl_buf, 0, bts2rd);
-
-            ret = fat_file_write(&fs_info->fat, fat_fd,
-                                 empty_space_offset * bts2rd,
-                                 bts2rd, fs_info->cl_buf);
-#if MSDOS_FIND_PRINT
-            printf ("MSFS:[9.4] clear write: %d\n", ret);
-#endif
-            if (ret == -1)
-              return ret;
-            else if (ret != bts2rd)
-              rtems_set_errno_and_return_minus_one(EIO);
-          }
+            uint32_t new_length;
+#if MSDOS_FIND_PRINT
+            printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
+#endif
+            ret = fat_file_read(&fs_info->fat, fat_fd,
+                                (empty_space_offset * bts2rd), bts2rd,
+                                fs_info->cl_buf);
+
+            if (ret != bts2rd)
+            {
+                if (ret != FAT_EOF)
+                    rtems_set_errno_and_return_minus_one(EIO);
+
+#if MSDOS_FIND_PRINT
+                printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
+#endif
+                ret = fat_file_extend (&fs_info->fat, fat_fd, false,
+                                       empty_space_offset * bts2rd, &new_length);
+
+                if (ret != RC_OK)
+                    return ret;
+
+#if MSDOS_FIND_PRINT
+                printf ("MSFS:[9.3] extended: %"PRIu32" <-> %"PRIu32"\n", new_length, empty_space_offset * bts2rd);
+#endif
+                if (new_length != (empty_space_offset * bts2rd))
+                    rtems_set_errno_and_return_minus_one(EIO);
+
+                memset(fs_info->cl_buf, 0, bts2rd);
+
+                bytes_written = fat_file_write(&fs_info->fat, fat_fd,
+                                               empty_space_offset * bts2rd,
+                                               bts2rd, fs_info->cl_buf);
+#if MSDOS_FIND_PRINT
+                printf ("MSFS:[9.4] clear write: %d\n", ret);
+#endif
+                if (bytes_written == -1)
+                    return -1;
+                else if (bytes_written != bts2rd)
+                    rtems_set_errno_and_return_minus_one(EIO);
+            }
         }
 
@@ -1467,12 +1752,12 @@
              * Time to write the short file name entry.
              */
-            if (lfn_entry == (lfn_entries + 1))
+            if (lfn_entry == (fat_entries + 1))
             {
                 /* get current cluster number */
-                int rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
-                                        empty_space_offset * bts2rd,
-                                        &dir_pos->sname.cln);
-                if (rc != RC_OK)
-                  return rc;
+                ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
+                                    empty_space_offset * bts2rd,
+                                    &dir_pos->sname.cln);
+                if (ret != RC_OK)
+                    return ret;
 
                 dir_pos->sname.ofs = dir_entry;
@@ -1480,9 +1765,9 @@
                 if (lfn_start.cln != FAT_FILE_SHORT_NAME)
                 {
-                  rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
-                                      lfn_start.cln * bts2rd,
-                                      &lfn_start.cln);
-                  if (rc != RC_OK)
-                    return rc;
+                    ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
+                                        lfn_start.cln * bts2rd,
+                                        &lfn_start.cln);
+                    if (ret != RC_OK)
+                        return ret;
                 }
 
@@ -1504,6 +1789,6 @@
             if (lfn_start.cln == FAT_FILE_SHORT_NAME)
             {
-              lfn_start.cln = empty_space_offset;
-              lfn_start.ofs = dir_entry;
+                lfn_start.cln = empty_space_offset;
+                lfn_start.ofs = dir_entry;
             }
 
@@ -1516,12 +1801,15 @@
 
             p = entry + 1;
-            n = name + (lfn_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY;
-
-            for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++)
+            n = name_converted + (fat_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR;
+
+#if MSDOS_FIND_PRINT
+            printf ("MSFS:[11] ");
+#endif
+            for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
             {
-                if (*n != 0)
+                if (!(*n == 0 && *(n+1) == 0))
                 {
                     *p = *n;
-                    n++;
+                    *(p+1) = *(n+1);
                 }
                 else
@@ -1531,4 +1819,8 @@
                     fill = 0xff;
                 }
+                n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
+#if MSDOS_FIND_PRINT
+                printf ( "'%c''%c'", *p, *(p+1) );
+#endif
 
                 switch (i)
@@ -1545,6 +1837,8 @@
                 }
             }
-
-            *MSDOS_DIR_ENTRY_TYPE(entry) = (lfn_entries - lfn_entry) + 1;
+#if MSDOS_FIND_PRINT
+            printf ( "\n" );
+#endif
+            *MSDOS_DIR_ENTRY_TYPE(entry) = (fat_entries - lfn_entry) + 1;
             if (lfn_entry == 1)
                 *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
@@ -1552,10 +1846,10 @@
         }
 
-        ret = fat_file_write(&fs_info->fat, fat_fd,
-                             (empty_space_offset * bts2rd) + empty_space_entry,
-                             length, fs_info->cl_buf + empty_space_entry);
-        if (ret == -1)
-            return ret;
-        else if (ret != length)
+        bytes_written = fat_file_write(&fs_info->fat, fat_fd,
+                                       (empty_space_offset * bts2rd) + empty_space_entry,
+                                       length, fs_info->cl_buf + empty_space_entry);
+        if (bytes_written == -1)
+            return -1;
+        else if (bytes_written != length)
             rtems_set_errno_and_return_minus_one(EIO);
 
@@ -1564,7 +1858,163 @@
         read_cluster = true;
     }
-
-    return 0;
-}
+    return ret;
+}
+
+int
+msdos_find_name_in_fat_file (
+    rtems_filesystem_mount_table_entry_t *mt_entry,
+    fat_file_fd_t                        *fat_fd,
+    bool                                  create_node,
+    const uint8_t                        *name_utf8,
+    int                                   name_utf8_len,
+    msdos_name_type_t                     name_type,
+    fat_dir_pos_t                        *dir_pos,
+    char                                 *name_dir_entry)
+{
+    int                                retval                     = 0;
+    msdos_fs_info_t                   *fs_info                    = mt_entry->fs_info;
+    ssize_t                            name_len_for_save;
+    ssize_t                            name_len_for_compare;
+    uint32_t                           bts2rd                     = 0;
+    uint32_t                           empty_space_offset         = 0;
+    uint32_t                           empty_space_entry          = 0;
+    uint32_t                           empty_space_count          = 0;
+    uint32_t                           dir_offset                 = 0;
+    unsigned int                       fat_entries;
+    rtems_dosfs_convert_control       *converter = fs_info->converter;
+    void                              *buffer = converter->buffer.data;
+    size_t                             buffer_size = converter->buffer.size;
+
+    assert(name_utf8_len > 0);
+
+    fat_dir_pos_init(dir_pos);
+
+
+
+    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;
+
+    switch ( name_type ) {
+        case MSDOS_NAME_SHORT:
+            name_len_for_compare = msdos_filename_utf8_to_short_name_for_compare (
+                converter,
+                name_utf8,
+                name_utf8_len,
+                buffer,
+                MSDOS_SHORT_NAME_LEN);
+            if (name_len_for_compare > 0) {
+                fat_entries = 0;
+            }
+            else
+                retval = -1;
+        break;
+        case MSDOS_NAME_LONG:
+            name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
+                converter,
+                name_utf8,
+                name_utf8_len,
+                buffer,
+                buffer_size);
+            if (name_len_for_save > 0) {
+                fat_entries = (name_len_for_save -1
+                               + (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR)) / (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR);
+                name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
+                  converter,
+                  name_utf8,
+                  name_utf8_len,
+                  buffer,
+                  buffer_size);
+                if (0 >= name_len_for_compare) {
+                    retval = -1;
+                }
+            }
+            else
+                retval = -1;
+        break;
+        case MSDOS_NAME_INVALID:
+        default:
+            errno = EINVAL;
+            retval = -1;
+        break;
+    }
+    if (retval == RC_OK) {
+      /* See if the file/directory does already exist */
+      retval = msdos_find_file_in_directory (
+          buffer,
+          name_len_for_compare,
+          name_len_for_save,
+          name_type,
+          fs_info,
+          fat_fd,
+          bts2rd,
+          create_node,
+          fat_entries,
+          name_dir_entry,
+          dir_pos,
+          &dir_offset,
+          &empty_space_offset,
+          &empty_space_entry,
+          &empty_space_count);
+    }
+    /* Create a non-existing file/directory if requested */
+    if (   retval == RC_OK
+        && create_node) {
+        switch (name_type) {
+          case MSDOS_NAME_SHORT:
+              name_len_for_save = msdos_filename_utf8_to_short_name_for_save (
+                  converter,
+                  name_utf8,
+                  name_utf8_len,
+                  buffer,
+                  MSDOS_SHORT_NAME_LEN);
+              if (name_len_for_save > 0 ) {
+                  fat_entries = 0;
+              }
+              else
+                  retval = -1;
+          break;
+          case MSDOS_NAME_LONG:
+              name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
+                  converter,
+                  name_utf8,
+                  name_utf8_len,
+                  buffer,
+                  buffer_size);
+              if (name_len_for_save > 0) {
+                fat_entries = (name_len_for_save -1
+                               + (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR)) / (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR);
+
+              }
+              else
+                  retval = -1;
+          break;
+          case MSDOS_NAME_INVALID:
+          default:
+              errno = EINVAL;
+              retval = -1;
+          break;
+        }
+        retval = msdos_add_file (
+            buffer,
+            name_type,
+            fs_info,
+            fat_fd,
+            bts2rd,
+            fat_entries,
+            name_dir_entry,
+            dir_pos,
+            dir_offset,
+            empty_space_offset,
+            empty_space_entry,
+            empty_space_count
+        );
+    }
+
+    return retval;
+}
+
 
 /* msdos_find_node_by_cluster_num_in_fat_file --
