[PATCH 1/2] dosfs: Interface changes for supporting UTF-8 file names
Ralf Kirchner
ralf.kirchner at embedded-brains.de
Fri Feb 1 09:41:58 UTC 2013
---
cpukit/libfs/Makefile.am | 3 +-
cpukit/libfs/src/dosfs/dosfs.h | 183 +++-
cpukit/libfs/src/dosfs/msdos.h | 62 +-
cpukit/libfs/src/dosfs/msdos_conv.c | 581 ++++++++++---
cpukit/libfs/src/dosfs/msdos_create.c | 3 +-
cpukit/libfs/src/dosfs/msdos_dir.c | 113 +--
cpukit/libfs/src/dosfs/msdos_fsunmount.c | 1 +
cpukit/libfs/src/dosfs/msdos_init.c | 194 ++++-
cpukit/libfs/src/dosfs/msdos_initsupp.c | 5 +-
cpukit/libfs/src/dosfs/msdos_misc.c | 910 ++++++++++++++------
.../src/dosfs/msdos_string_handling_no_convert.c | 166 ++++
11 Dateien geändert, 1707 Zeilen hinzugefügt(+), 514 Zeilen entfernt(-)
create mode 100644 cpukit/libfs/src/dosfs/msdos_string_handling_no_convert.c
diff --git a/cpukit/libfs/Makefile.am b/cpukit/libfs/Makefile.am
index 7535b5a..be58301 100644
--- a/cpukit/libfs/Makefile.am
+++ b/cpukit/libfs/Makefile.am
@@ -82,7 +82,8 @@ libdosfs_a_SOURCES += src/dosfs/msdos_create.c src/dosfs/msdos_dir.c \
src/dosfs/msdos_mknod.c src/dosfs/msdos_node_type.c \
src/dosfs/msdos_rmnod.c \
src/dosfs/msdos_conv.c src/dosfs/msdos.h src/dosfs/msdos_format.c \
- src/dosfs/dosfs.h src/dosfs/msdos_rename.c
+ src/dosfs/dosfs.h src/dosfs/msdos_rename.c \
+ src/dosfs/msdos_string_handling_no_convert.c
endif
# RFS
diff --git a/cpukit/libfs/src/dosfs/dosfs.h b/cpukit/libfs/src/dosfs/dosfs.h
index 211fc2d..190a21f 100644
--- a/cpukit/libfs/src/dosfs/dosfs.h
+++ b/cpukit/libfs/src/dosfs/dosfs.h
@@ -25,8 +25,189 @@
extern "C" {
#endif
+typedef struct {
+ uint8_t *file_name_scratch_buf;
+ void *optional_args;
+} rtems_dosfs_string_context;
+
+/**
+ * @brief Converts from UTF-8 into a specific code page
+ * @param[in/out] string_arg An optional argument
+ * @param[in] str A well-formed UTF-8 string to be converted.
+ * @param[in] strsize The size of the string in bytes
+ * (inludes '\0' if any).
+ * @param[out] buffer The address the converted string will get copied to.
+ * @param[in/out] bufsize The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ * @retval Pointer to the resulting string if successful. NULL and errno
+ * set if not successful.
+ */
+typedef char* (*rtems_dosfs_utf8_to_codepage) (
+ void* string_arg, const uint8_t *str, size_t strlen, char *buffer, size_t *bufsize);
+
+/**
+ * @brief Converts from a specific code page into UTF-8
+ * @param[in/out] string_arg An optional argument.
+ * @param[in] str A well-formed string in code page format.
+ * @param[in] strsize The size of the string in bytes
+ * (inludes '\0' if any).
+ * @param[out] buffer The address the converted string will get copied to.
+ * @param[in/out] bufsize The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ * @retval Pointer to the resulting string if successful. NULL and errno
+ * set if not successful.
+ */
+typedef uint8_t* (*rtems_dosfs_codepage_to_utf8) (
+ void* string_arg, const char *str, size_t strlen, uint8_t *buffer, size_t *bufsize);
+
+/**
+ * @brief Converts from UTF-8 to UTF-16
+ * @param[in/out] string_arg An optional argument.
+ * @param[in] str A well-formed UTF-8 string to be converted.
+ * @param[in] strsize The size of the string in bytes
+ * (inludes '\0' if any).
+ * @param[out] buffer The address the converted string will get copied to
+ * @param[in/out] bufsize The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ * @retval Pointer to the resulting string if successful. NULL and errno
+ * set if not successful.
+ */
+typedef uint16_t* (*rtems_dosfs_utf8_to_utf16) (
+ void* string_arg, const uint8_t *str, size_t strsize, uint16_t *buffer, size_t *bufsize);
+
+/**
+ * @brief Converts from UTF-16 to UTF-8.
+ * @param[in/out] string_arg An optional argument.
+ * @param[in] str A well-formed UTF-16 string to be converted.
+ * @param[in] strsize The size of the string in bytes
+ * (inludes '\0' if any).
+ * @param[out] buffer The address the converted string will get copied to.
+ * @param[in/out] bufsize The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer
+ * @retval Pointer to the resulting string if successful. NULL and errno
+ * set if not successful.
+ */
+typedef uint8_t* (*rtems_dosfs_utf16_to_utf8) (
+ void* string_arg, const uint16_t *str, size_t strsize, uint8_t *buffer, size_t *bufsize);
+
+/* @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] string_arg An optional argument to the conversion method.
+ * @param[in] str A well-formed UTF-8 string.
+ * @param[in] strsize The size of the string in UTF-8 characters.
+ * @param[out] buffer The address the converted string will get copied to.
+ * @param[in/out] bufsize The size of the buffer in bytes respectively the
+ * number of bytes written to the buffer.
+ * @retval A pointer to the resulting string if successful. NULL and errno
+ * set if not successful.
+ */
+typedef uint8_t* (*rtems_dosfs_utf8_normalize_and_fold) (
+ void* string_arg, const uint8_t* str, size_t strsize, uint8_t* buffer, size_t *bufsize);
+
+/**
+ * @brief FAT file system string handling.
+ */
+typedef struct {
+ /* @brief Converts from UTF-8 into a specific code page. */
+ rtems_dosfs_utf8_to_codepage utf8_to_codepage;
+ /* @brief Converts from specific code page into UTF-8. */
+ rtems_dosfs_codepage_to_utf8 codepage_to_utf8;
+ /* @brief Converts from UTF-8 into UTF-16. */
+ rtems_dosfs_utf8_to_utf16 utf8_to_utf16;
+ /* @brief Converts from UTF-16 into UTF-8. */
+ rtems_dosfs_utf16_to_utf8 utf16_to_utf8;
+ /* @brief Normalizes and folds a UTF-8 string. */
+ rtems_dosfs_utf8_normalize_and_fold utf8_normalize_and_fold;
+} rtems_dosfs_string_handling;
+
+char* msdos_utf8_to_codepage_no_convert (
+ void* string_arg, const uint8_t *str, const size_t strsize, char *buffer, size_t *bufsize);
+
+uint8_t* msdos_codepage_to_utf8_no_convert (
+ void* string_arg, const char *str, const size_t strsize, uint8_t *buffer, size_t *bufsize);
+
+uint16_t* msdos_utf8_to_utf16_no_convert (
+ void* string_arg, const uint8_t *str, const size_t strsize, uint16_t *buffer, size_t *bufsize);
+
+uint8_t* msdos_utf16_to_utf8_no_convert (
+ void* string_arg, const uint16_t *str, const size_t strsize, uint8_t *buffer, size_t *buffsize);
+
+uint8_t* msdos_utf8_normalize_and_fold (
+ void* string_arg, const uint8_t* str, const size_t strsize, uint8_t* buffer, size_t *bufsize);
+
+/* forward declaration */
+typedef struct rtems_dosfs_string_options_s rtems_dosfs_string_options;
+
+/* @brief Cleanup handler for string options */
+typedef void (*rtems_dosfs_string_options_cleanup) (
+ rtems_dosfs_string_options* string_opts);
+
+/**
+ * @brief FAT file system mount options.
+ */
+typedef struct rtems_dosfs_string_options_s {
+ /* @brief struct of pointers to string handling methods to be applied for
+ * file/directory names */
+ rtems_dosfs_string_handling string_handling;
+
+ /* @brief Context for string handling*/
+ rtems_dosfs_string_context string_handling_ctx;
+
+ /* @brief Cleanup handler for string options */
+ rtems_dosfs_string_options_cleanup cleanup_handler;
+} rtems_dosfs_string_options;
+
+typedef struct {
+ rtems_dosfs_string_options *string_opts;
+} rtems_dosfs_mount_options;
+
+/**
+ * @brief Initializes mount options.
+ *
+ * @param[in/out] mount_options The mount options to be initialized.
+ * @param[in] string_handling_arg A pointer to optional string handling
+ * argument.
+ * @param[in] utf8_to_codepage A function pointer to conversion method from
+ * UTF-8 to a code page.
+ * @param[in] codepage_to_utf8 A function pointer to conversion method from a
+ * code page to UTF-8.
+ * @param[in] utf8_to_utf16 A function pointer to conversion method from
+ * UTF-8 to UTF-16.
+ * @param[in] utf16_to_utf8 A function pointer to conversion method from
+ * UTF-16 to UTF-8.
+ * @param[in] utf8_normalize_and_fold A function pointer to conversion method
+ * which normalizes and folds a UTF-8 string.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred. The @c errno indicates the error.
+ * @see rtems_dosfs_initialize().
+ */
+int
+rtems_dosfs_mount_options_init (
+ rtems_dosfs_mount_options *mount_options,
+ void *string_handling_arg,
+ 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
+);
+
+/**
+ * @brief Initializes a FAT file system.
+ *
+ * @param[in] mt_entry The entry in the mount table.
+ * @param[in] mount_opts NULL or pointer to a rtems_dosfs_mount_options.
+ *
+ * @retval 0 Successful operation.
+ * @retval -1 An error occurred. The @c errno indicates the error.
+ * @see rtems_dosfs_mount_options_init().
+ */
int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
- const void *data);
+ const void *mount_opts);
/**
* @defgroup rtems_msdos_format DOSFS Support
diff --git a/cpukit/libfs/src/dosfs/msdos.h b/cpukit/libfs/src/dosfs/msdos.h
index 9465d26..2a41b47 100644
--- a/cpukit/libfs/src/dosfs/msdos.h
+++ b/cpukit/libfs/src/dosfs/msdos.h
@@ -20,6 +20,7 @@
#include <rtems.h>
#include <rtems/libio_.h>
+#include <rtems/dosfs.h>
#include "fat.h"
#include "fat_file.h"
@@ -67,6 +68,7 @@ typedef struct msdos_fs_info_s
* just placeholder
* for anything
*/
+ rtems_dosfs_string_options string_opts; /* string handling options passed to mount() */
} msdos_fs_info_t;
/* a set of routines that handle the nodes which are directories */
@@ -183,6 +185,8 @@ typedef rtems_filesystem_node_types_t msdos_node_type_t;
/*
* 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 */
#define MSDOS_SHORT_EXT_LEN 3 /* 3 characters */
@@ -190,9 +194,18 @@ typedef rtems_filesystem_node_types_t msdos_node_type_t;
MSDOS_SHORT_EXT_LEN) /* 11 chars */
#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_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 */
extern const char *const MSDOS_DOTDOT_NAME; /* ".", padded to MSDOS_NAME chars */
@@ -213,6 +226,14 @@ typedef enum msdos_token_types_e
MSDOS_INVALID_TOKEN
} msdos_token_types_t;
+typedef enum
+{
+ MSDOS_STRING_TYPE_CODEPAGE,
+ MSDOS_STRING_TYPE_UTF8,
+
+ MSDOS_STRING_TYPE_NUMBER_OF
+} msdos_string_types;
+
/* Others macros */
#define MSDOS_RES_NT_VALUE 0x00
#define MSDOS_INIT_DIR_SIZE 0x00
@@ -306,7 +327,8 @@ int msdos_initialize_support(
rtems_filesystem_mount_table_entry_t *temp_mt_entry,
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_string_options *string_options
);
int msdos_file_close(rtems_libio_t *iop /* IN */);
@@ -384,10 +406,42 @@ int msdos_get_name_node(
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,
+msdos_name_type_t msdos_long_to_short(rtems_dosfs_string_options *string_opts,
+ const char *lfn, int lfn_len,
char* sfn, int sfn_len);
-int msdos_filename_unix2dos(const char *un, int unlen, char *dn);
+int
+msdos_filename_utf8_to_short_name (
+ rtems_dosfs_string_options *string_opts,
+ const uint8_t *utf8_name,
+ const size_t utf8_name_size,
+ void *short_name,
+ const size_t short_name_size,
+ const msdos_string_types short_name_string_type);
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_compare (
+ rtems_dosfs_string_options *string_opts,
+ 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_string_options *string_opts,
+ 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(
unsigned int tsp, uint16_t *ddp,
@@ -427,7 +481,7 @@ 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 char *name,
+ const uint8_t *name_utf8,
int name_len,
msdos_name_type_t name_type,
fat_dir_pos_t *dir_pos,
diff --git a/cpukit/libfs/src/dosfs/msdos_conv.c b/cpukit/libfs/src/dosfs/msdos_conv.c
index 7549c42..73f95f0 100644
--- a/cpukit/libfs/src/dosfs/msdos_conv.c
+++ b/cpukit/libfs/src/dosfs/msdos_conv.c
@@ -28,12 +28,29 @@
#include "config.h"
#endif
+#include <ctype.h>
#include <rtems.h>
#include "msdos.h"
/* #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 0x0000
+#define UTF16_NULL_SIZE 2
+#define UTF16_BLANK 0x0020
+#define UTF16_BLANK_SIZE 2
+#define UTF16_FULL_STOP 0x002e
+#define UTF16_FULL_STOP_SIZE 2
+
/*
* Days in each month in a regular year.
*/
@@ -174,150 +191,450 @@ msdos_date_dos2unix(unsigned int dd, unsigned int dt)
return seconds + lastseconds;
}
-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, 0x73, 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)
+
+typedef uint16_t (*msdos_get_valid_character_from_utf16) (
+ const uint16_t character);
+
+
+static uint16_t
+msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
{
- int i;
- uint8_t c;
+ uint16_t retval = 0x0000;
+ uint16_t tmp_char = 0x0000;
- /*
- * Fill the dos filename string with blanks. These are DOS's pad
- * characters.
- */
- for (i = 0; i <= 10; i++)
- dn[i] = ' ';
+ if ( utf16_character <= 0x00ff ) {
+ switch (utf16_character)
+ {
+ 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 = utf16_character;
+ break;
+ default:
+ tmp_char = codepage_valid_char_map[utf16_character];
+ retval = 0x00ff & tmp_char;
+ break;
+ }
+ }
+ else
+ retval = utf16_character;
+
+ return retval;
+}
+
+typedef char (*msdos_get_valid_character_from_utf8) (
+ const uint8_t character);
+
+static char
+msdos_get_valid_codepage_filename_character (const uint8_t character)
+{
+ return codepage_valid_char_map[(unsigned int)character];
+}
+
+static char
+msdos_get_valid_utf8_filename_character_from_utf8 (const uint8_t character)
+{
+ return (char)character;
+}
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_compare (
+ rtems_dosfs_string_options *string_opts,
+ 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;
+ const uint8_t *name_ptr = utf8_name;
+ size_t name_size = utf8_name_size;
+ size_t dest_size = long_name_size;
+ int i;
+
+ /*
+ * Fill the UTF-8 filename string with NULLs. These are DOS's pad
+ * characters for long file names.
+ */
+ for (i = 0; i < long_name_size; ++i)
+ long_name[i] = UTF16_NULL;
+ /*
+ * The filenames "." and ".." are handled specially, since they
+ * don't follow dos filename rules.
+ */
+ if ( name_ptr[0] == UTF8_FULL_STOP
+ && name_size == UTF8_FULL_STOP_SIZE) {
+ long_name[0] = UTF8_FULL_STOP;
+ returned_size = UTF8_FULL_STOP_SIZE;
+ }
+ else if ( name_ptr[0] == UTF8_FULL_STOP
+ && name_ptr[1] == UTF8_FULL_STOP
+ && name_size == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
+ long_name[0] = UTF8_FULL_STOP;
+ long_name[1] = UTF8_FULL_STOP;
+ returned_size = 2 * UTF8_FULL_STOP_SIZE;
+ }
+ else {
+ /*
+ * Remove any dots from the end of a file name.
+ */
+ for ( i = name_size - 1 - UTF8_FULL_STOP_SIZE;
+ name_size >= UTF8_FULL_STOP_SIZE
+ && utf8_name[i] == UTF8_FULL_STOP;) {
+ name_size -= UTF8_FULL_STOP_SIZE;
+ i -= UTF8_FULL_STOP_SIZE;
+ }
+ if (NULL != string_opts->string_handling.utf8_normalize_and_fold (
+ string_opts->string_handling_ctx.optional_args,
+ utf8_name,
+ name_size,
+ long_name,
+ &dest_size) ) {
+ returned_size = (ssize_t)dest_size;
+ }
+ else
+ eno = EINVAL;
+ }
+
+ if ( eno != 0 ) {
+ errno = eno;
+ return -1;
+ }
+
+ return returned_size;
+ }
+
+ssize_t
+msdos_filename_utf8_to_long_name_for_save (
+ rtems_dosfs_string_options *string_opts,
+ 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;
+
+ /*
+ * Fill the UTF-16 filename string with NULLs. These are DOS's pad
+ * characters for long file names.
+ */
+ for (i = 0; i < name_size_tmp; ++i)
+ long_name[i] = UTF16_NULL;
+
+ name_size_tmp = long_name_size;
+ /*
+ * The filenames "." and ".." are handled specially, since they
+ * don't follow dos filename rules.
+ */
+ if ( utf8_name[0] == UTF8_FULL_STOP
+ && name_size == UTF8_FULL_STOP_SIZE) {
+ long_name[0] = UTF16_FULL_STOP;
+ returned_size = UTF16_FULL_STOP_SIZE;
+ }
+ else if ( utf8_name[0] == UTF8_FULL_STOP
+ && utf8_name[1] == UTF8_FULL_STOP
+ && name_size == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
+ long_name[0] = UTF16_FULL_STOP;
+ long_name[1] = UTF16_FULL_STOP;
+ returned_size = 2 * UTF16_FULL_STOP_SIZE;
+ }
+ else {
+ /*
+ * Remove any dots from the end of a file name.
+ */
+ for ( i = name_size - 1 - UTF8_FULL_STOP_SIZE;
+ name_size >= UTF8_FULL_STOP_SIZE
+ && utf8_name[i] == UTF8_FULL_STOP;) {
+ name_size -= UTF8_FULL_STOP_SIZE;
+ i -= UTF8_FULL_STOP_SIZE;
+ }
+ /*
+ * Finally convert from UTF-8 to UTF-16
+ */
+ if (NULL != string_opts->string_handling.utf8_to_utf16 (
+ string_opts->string_handling_ctx.optional_args,
+ utf8_name,
+ name_size,
+ &long_name[0],
+ &name_size_tmp) ) {
+ name_size = name_size_tmp;
+ }
+ else
+ eno = EINVAL;
+
+ 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;
+ }
+ }
+
+ if ( eno != 0 ) {
+ errno = eno;
+ return -1;
+ }
+
+ return returned_size;
+ }
+
+int
+msdos_filename_utf8_to_short_name (
+ rtems_dosfs_string_options *string_opts,
+ const uint8_t *utf8_name,
+ const size_t utf8_name_size,
+ void *short_name,
+ const size_t short_name_size,
+ const msdos_string_types short_name_string_type)
+{
+ const size_t CP_NAME_TMP_BUF_SIZE = MSDOS_SHORT_NAME_LEN +1;
+ int returned_size = 0;
+ int eno = 0;
+ unsigned int i;
+ char c;
+ char name_to_format_buf[CP_NAME_TMP_BUF_SIZE];
+ const uint8_t *name_ptr = utf8_name;
+ size_t name_size = utf8_name_size;
+ size_t name_size_tmp = MSDOS_NAME_MAX_UTF8_LFN_BYTES;
+ msdos_get_valid_character_from_utf8 get_valid_character = NULL;
+ char *dest_ptr = (char*)short_name;
+ char *cp_name_ptr = NULL;
- /*
- * 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;
- }
/*
- * Remove any dots from the start of a file name.
+ * The filenames "." and ".." are handled specially, since they
+ * don't follow dos filename rules.
*/
- while (unlen && (*un == '.')) {
- un++;
- unlen--;
- }
+ if ( name_ptr[0] == UTF8_FULL_STOP
+ && name_size == UTF8_FULL_STOP_SIZE) {
+ dest_ptr[0] = '.';
+ returned_size = sizeof ( '.' );
+ }
+ else if ( name_ptr[0] == UTF8_FULL_STOP
+ && name_ptr[1] == UTF8_FULL_STOP
+ && name_size == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
+ dest_ptr[0] = '.';
+ dest_ptr[1] = '.';
+ returned_size = 2 * sizeof ( '.' );
+ }
+ else {
+ /*
+ * Remove any dots from the start of a file name.
+ */
+ while ( name_size >= UTF8_FULL_STOP_SIZE
+ && *name_ptr == UTF8_FULL_STOP) {
+ name_ptr += UTF8_FULL_STOP_SIZE;
+ name_size -= UTF8_FULL_STOP_SIZE;
+ }
- /*
- * 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--;
- }
+ /*
+ * Normalize the name and convert to lower case
+ */
+ if (NULL != string_opts->string_handling.utf8_normalize_and_fold (
+ string_opts->string_handling_ctx.optional_args,
+ name_ptr,
+ name_size,
+ &string_opts->string_handling_ctx.file_name_scratch_buf[0]/*&utf8_name_tmp[0]*/,
+ &name_size_tmp) ) {
+ name_ptr = &string_opts->string_handling_ctx.file_name_scratch_buf[0]/*&utf8_name_tmp[0]*/;
+ name_size = name_size_tmp;
+ switch (short_name_string_type)
+ {
+ case MSDOS_STRING_TYPE_CODEPAGE:
+ /*
+ * Finally convert from UTF-8 to codepage
+ */
+ name_size_tmp = sizeof ( name_to_format_buf );
+ cp_name_ptr = string_opts->string_handling.utf8_to_codepage (
+ string_opts->string_handling_ctx.optional_args,
+ name_ptr,
+ name_size,
+ &name_to_format_buf[0],
+ &name_size_tmp);
+ if ( cp_name_ptr == NULL && name_size_tmp == sizeof ( name_to_format_buf ) ) {
+ cp_name_ptr = &name_to_format_buf[0];
+ errno = 0;
+ }
+ if ( NULL != cp_name_ptr ) {
+ name_ptr = ( typeof( name_ptr ) )(&name_to_format_buf[0]);
+ name_size = name_size_tmp;
+ get_valid_character = msdos_get_valid_codepage_filename_character;
+ for (i = 0; i < name_size; ++i)
+ name_to_format_buf[i] = toupper ( (int)(name_to_format_buf[i]) );
+ }
+ else
+ eno = EINVAL;
+ break;
+ case MSDOS_STRING_TYPE_UTF8:
+ get_valid_character = msdos_get_valid_utf8_filename_character_from_utf8;
+ break;
+ case MSDOS_STRING_TYPE_NUMBER_OF:
+ default:
+ eno = EINVAL;
+ break;
+ }
+ if ( eno == 0 ) {
+ /*
+ * 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 )
+ eno = EINVAL;
+ else if ( 0xE5 == *name_ptr )
+ dest_ptr[0] = 0x05;
+ else if (0 != (c = get_valid_character( *name_ptr ) ) )
+ dest_ptr[0] = c;
+ else
+ eno = EINVAL;
+ if ( eno == 0 ) {
+ ++name_ptr;
+ ++returned_size;
+ --name_size;
+ /*
+ * Validate and assign all other characters of the name part
+ */
+ for (i = 1; i <= 7 && name_size && (c = get_valid_character ( *name_ptr ) ) && c != '.'; ++i) {
+ dest_ptr[i] = c;
+ ++name_ptr;
+ ++returned_size;
+ --name_size;
+ }
+ if ( c == 0 && name_size > 0)
+ eno = EINVAL;
+ /*
+ * Strip any further characters up to a '.' or the end of the
+ * string.
+ */
+ while (name_size && (c = get_valid_character ( *name_ptr ) ) ) {
+ name_ptr++;
+ name_size--;
+ /* Make sure we've skipped over the dot before stopping. */
+ if (c == '.')
+ break;
+ }
+ if ( c == 0 && name_size > 0)
+ eno = EINVAL;
+ /*
+ * Copy in the extension part of the name, if any.
+ */
+ for (i = 8; i <= 10 && name_size && (c = get_valid_character ( *name_ptr) ); i++) {
+ dest_ptr[i] = c;
+ ++name_ptr;
+ ++returned_size;
+ name_size--;
+ }
+ if ( c == 0 && name_size > 0)
+ eno = EINVAL;
+ /*
+ * Fill up with blanks. These are DOS's pad characters.
+ */
+ if ( eno == 0 ) {
+ for ( i = returned_size; i < short_name_size; ++i ) {
+ dest_ptr[i] = ' ';
+ ++returned_size;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ eno = errno;
- /*
- * 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;
+ if ( eno != 0 ) {
+ errno = eno;
+ return -1;
+ }
+
+ return returned_size;
}
diff --git a/cpukit/libfs/src/dosfs/msdos_create.c b/cpukit/libfs/src/dosfs/msdos_create.c
index 886dd40..2e813b7 100644
--- a/cpukit/libfs/src/dosfs/msdos_create.c
+++ b/cpukit/libfs/src/dosfs/msdos_create.c
@@ -90,7 +90,8 @@ msdos_creat_node(const rtems_filesystem_location_info_t *parent_loc,
rtems_set_errno_and_return_minus_one(ENAMETOOLONG);
}
- name_type = msdos_long_to_short (name, name_len,
+ name_type = msdos_long_to_short (&fs_info->string_opts,
+ name, name_len,
MSDOS_DIR_NAME(short_node),
MSDOS_NAME_MAX);
if (name_type == MSDOS_NAME_INVALID) {
diff --git a/cpukit/libfs/src/dosfs/msdos_dir.c b/cpukit/libfs/src/dosfs/msdos_dir.c
index fd9ca40..f3dc42a 100644
--- a/cpukit/libfs/src/dosfs/msdos_dir.c
+++ b/cpukit/libfs/src/dosfs/msdos_dir.c
@@ -24,6 +24,7 @@
#include <rtems/libio_.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <assert.h>
#include <dirent.h>
@@ -130,9 +131,13 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
int rc = RC_OK;
rtems_status_code sc = RTEMS_SUCCESSFUL;
msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
+ const rtems_dosfs_string_handling *string_handlers = &fs_info->string_opts.string_handling;
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;
+ uint16_t *lfn_buf = (uint16_t*)(&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0]);
+ char *sfn_buf = (char*)(&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0]);
uint32_t start = 0;
ssize_t ret = 0;
uint32_t cmpltd = 0;
@@ -142,6 +147,8 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
uint32_t lfn_start = FAT_FILE_SHORT_NAME;
uint8_t lfn_checksum = 0;
int lfn_entries = 0;
+ size_t string_size = sizeof(tmp_dirent.d_name);
+ bool is_first_entry;
/*
* cast start and count - protect against using sizes that are not exact
@@ -167,7 +174,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
if (sc != RTEMS_SUCCESSFUL)
rtems_set_errno_and_return_minus_one(EIO);
- while (count > 0)
+ while (count > 0 && cmpltd >= 0)
{
/*
* fat-file is already opened by open call, so read it
@@ -183,7 +190,7 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
rtems_set_errno_and_return_minus_one(EIO);
}
- 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;
@@ -213,15 +220,14 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
MSDOS_ATTR_LFN)
{
- int o;
- char* p;
- int q;
+ int offset_lfn;
/*
* Is this is the first entry of a LFN ?
*/
if (lfn_start == FAT_FILE_SHORT_NAME)
{
+ is_first_entry = true;
/*
* The first entry must have the last long entry flag set.
*/
@@ -241,9 +247,12 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
*/
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;
/*
* If the entry number or the check sum do not match
@@ -262,7 +271,9 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
/*
* 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
* trailing nul character. We need to range check the length to
@@ -270,32 +281,13 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
*/
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],
+ MSDOS_NAME_MAX_LFN_BYTES - offset_lfn,
+ is_first_entry
+ );
}
else
{
@@ -344,9 +336,10 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
tmp_dirent.d_ino = tmp_fat_fd->ino;
/*
- * 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)
{
@@ -359,6 +352,18 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
if (lfn_entries || (lfn_checksum != cs))
lfn_start = FAT_FILE_SHORT_NAME;
+
+ if (NULL != string_handlers->utf16_to_utf8(
+ fs_info->string_opts.string_handling_ctx.optional_args,
+ lfn_buf,
+ tmp_lfn_len,
+ (uint8_t*)(&tmp_dirent.d_name[0]),
+ &string_size)) {
+ tmp_dirent.d_namlen = string_size;
+ }
+ else
+ lfn_start = FAT_FILE_SHORT_NAME;
+
}
if (lfn_start == FAT_FILE_SHORT_NAME)
@@ -368,25 +373,33 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
* to 0..8 + 1dot + 0..3 format
*/
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);
+ sfn_buf, entry); /* src text */
+ if (NULL != fs_info->string_opts.string_handling.codepage_to_utf8 (
+ fs_info->string_opts.string_handling_ctx.optional_args,
+ sfn_buf,
+ tmp_dirent.d_namlen,
+ (uint8_t*)(&tmp_dirent.d_name[0]),
+ &string_size ) ) {
+ tmp_dirent.d_namlen = string_size;
+ }
+ else
+ cmpltd = -1;
}
- memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
+ 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));
+ 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;
+ /* 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;
+ }
}
}
diff --git a/cpukit/libfs/src/dosfs/msdos_fsunmount.c b/cpukit/libfs/src/dosfs/msdos_fsunmount.c
index 90a8073..f8fd52f 100644
--- a/cpukit/libfs/src/dosfs/msdos_fsunmount.c
+++ b/cpukit/libfs/src/dosfs/msdos_fsunmount.c
@@ -54,6 +54,7 @@ msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
fat_shutdown_drive(&fs_info->fat);
rtems_semaphore_delete(fs_info->vol_sema);
+ fs_info->string_opts.cleanup_handler ( &fs_info->string_opts );
free(fs_info->cl_buf);
free(temp_mt_entry->fs_info);
}
diff --git a/cpukit/libfs/src/dosfs/msdos_init.c b/cpukit/libfs/src/dosfs/msdos_init.c
index eb46141..96ea7fc 100644
--- a/cpukit/libfs/src/dosfs/msdos_init.c
+++ b/cpukit/libfs/src/dosfs/msdos_init.c
@@ -10,7 +10,7 @@
* Author: Eugeny S. Mints <Eugeny.Mints at oktet.ru>
*
* Modifications to support reference counting in the file system are
- * Copyright (c) 2012 embedded brains GmbH.
+ * Copyright (c) 2012, 2013 embedded brains GmbH.
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
@@ -21,61 +21,142 @@
#include "config.h"
#endif
+#include <assert.h>
#include <rtems/libio_.h>
#include "dosfs.h"
#include "msdos.h"
-static int msdos_clone_node_info(rtems_filesystem_location_info_t *loc)
+static int msdos_clone_node_info( rtems_filesystem_location_info_t *loc )
{
- fat_file_fd_t *fat_fd = loc->node_access;
+ fat_file_fd_t *fat_fd = loc->node_access;
- return fat_file_reopen(fat_fd);
+
+ return fat_file_reopen( fat_fd );
}
-const rtems_filesystem_operations_table msdos_ops = {
- .lock_h = msdos_lock,
- .unlock_h = msdos_unlock,
- .eval_path_h = msdos_eval_path,
- .link_h = rtems_filesystem_default_link,
+const rtems_filesystem_operations_table msdos_ops = {
+ .lock_h = msdos_lock,
+ .unlock_h = msdos_unlock,
+ .eval_path_h = msdos_eval_path,
+ .link_h = rtems_filesystem_default_link,
.are_nodes_equal_h = rtems_filesystem_default_are_nodes_equal,
- .node_type_h = msdos_node_type,
- .mknod_h = msdos_mknod,
- .rmnod_h = msdos_rmnod,
- .fchmod_h = rtems_filesystem_default_fchmod,
- .chown_h = rtems_filesystem_default_chown,
- .clonenod_h = msdos_clone_node_info,
- .freenod_h = msdos_free_node_info,
- .mount_h = rtems_filesystem_default_mount,
- .fsmount_me_h = rtems_dosfs_initialize,
- .unmount_h = rtems_filesystem_default_unmount,
- .fsunmount_me_h = msdos_shut_down,
- .utime_h = rtems_filesystem_default_utime,
- .symlink_h = rtems_filesystem_default_symlink,
- .readlink_h = rtems_filesystem_default_readlink,
- .rename_h = msdos_rename,
- .statvfs_h = rtems_filesystem_default_statvfs
+ .node_type_h = msdos_node_type,
+ .mknod_h = msdos_mknod,
+ .rmnod_h = msdos_rmnod,
+ .fchmod_h = rtems_filesystem_default_fchmod,
+ .chown_h = rtems_filesystem_default_chown,
+ .clonenod_h = msdos_clone_node_info,
+ .freenod_h = msdos_free_node_info,
+ .mount_h = rtems_filesystem_default_mount,
+ .fsmount_me_h = rtems_dosfs_initialize,
+ .unmount_h = rtems_filesystem_default_unmount,
+ .fsunmount_me_h = msdos_shut_down,
+ .utime_h = rtems_filesystem_default_utime,
+ .symlink_h = rtems_filesystem_default_symlink,
+ .readlink_h = rtems_filesystem_default_readlink,
+ .rename_h = msdos_rename,
+ .statvfs_h = rtems_filesystem_default_statvfs
};
-void msdos_lock(const rtems_filesystem_mount_table_entry_t *mt_entry)
+void msdos_lock( const rtems_filesystem_mount_table_entry_t *mt_entry )
{
- msdos_fs_info_t *fs_info = mt_entry->fs_info;
- rtems_status_code sc = rtems_semaphore_obtain(
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ rtems_status_code sc = rtems_semaphore_obtain(
fs_info->vol_sema,
RTEMS_WAIT,
RTEMS_NO_TIMEOUT
- );
- if (sc != RTEMS_SUCCESSFUL) {
- rtems_fatal_error_occurred(0xdeadbeef);
+ );
+
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ rtems_fatal_error_occurred( 0xdeadbeef );
+ }
+}
+
+void msdos_unlock( const rtems_filesystem_mount_table_entry_t *mt_entry )
+{
+ msdos_fs_info_t *fs_info = mt_entry->fs_info;
+ rtems_status_code sc = rtems_semaphore_release( fs_info->vol_sema );
+
+
+ if ( sc != RTEMS_SUCCESSFUL ) {
+ rtems_fatal_error_occurred( 0xdeadbeef );
}
}
-void msdos_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
+static void msdos_string_options_cleanup(
+ rtems_dosfs_string_options *string_opts )
{
- msdos_fs_info_t *fs_info = mt_entry->fs_info;
- rtems_status_code sc = rtems_semaphore_release(fs_info->vol_sema);
- if (sc != RTEMS_SUCCESSFUL) {
- rtems_fatal_error_occurred(0xdeadbeef);
+ if ( string_opts != NULL ) {
+ if ( string_opts->string_handling_ctx.file_name_scratch_buf != NULL ) {
+ free( string_opts->string_handling_ctx.file_name_scratch_buf );
+ string_opts->string_handling_ctx.file_name_scratch_buf = NULL;
+ }
+ }
+}
+
+static int rtems_dosfs_string_options_init(
+ rtems_dosfs_string_options *opts,
+ void *string_handling_arg,
+ const rtems_dosfs_utf8_to_codepage utf8_to_codepage,
+ const rtems_dosfs_codepage_to_utf8 codepage_to_utf8,
+ const rtems_dosfs_utf8_to_utf16 utf8_to_utf16,
+ const rtems_dosfs_utf16_to_utf8 utf16_to_utf8,
+ const rtems_dosfs_utf8_normalize_and_fold utf8_normalize_and_fold )
+{
+ int eno = 0;
+
+
+ assert( opts != NULL );
+ assert( utf8_to_codepage != NULL );
+ assert( codepage_to_utf8 != NULL );
+ assert( utf8_to_utf16 != NULL );
+ assert( utf16_to_utf8 != NULL );
+ assert( utf8_normalize_and_fold != NULL );
+
+ opts->string_handling_ctx.file_name_scratch_buf = calloc(
+ MSDOS_NAME_MAX_UTF8_LFN_BYTES, sizeof( uint8_t ) );
+
+ if ( opts->string_handling_ctx.file_name_scratch_buf != NULL ) {
+ opts->string_handling_ctx.optional_args = NULL;
+ opts->cleanup_handler =
+ (rtems_dosfs_string_options_cleanup) msdos_string_options_cleanup;
+ opts->string_handling.utf8_to_codepage = utf8_to_codepage;
+ opts->string_handling.codepage_to_utf8 = codepage_to_utf8;
+ opts->string_handling.utf8_to_utf16 = utf8_to_utf16;
+ opts->string_handling.utf16_to_utf8 = utf16_to_utf8;
+ opts->string_handling.utf8_normalize_and_fold = utf8_normalize_and_fold;
+ opts->string_handling_ctx.optional_args = string_handling_arg;
+ } else
+ eno = ENOMEM;
+
+ if ( eno != 0 ) {
+ errno = eno;
+ return -1;
}
+
+ return 0;
+}
+
+int rtems_dosfs_mount_options_init(
+ rtems_dosfs_mount_options *mount_options,
+ void *string_handling_arg,
+ 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 )
+{
+ assert( mount_options != NULL );
+
+ return rtems_dosfs_string_options_init(
+ mount_options->string_opts,
+ string_handling_arg,
+ utf8_to_codepage,
+ codepage_to_utf8,
+ utf8_to_utf16,
+ utf16_to_utf8,
+ utf8_normalize_and_fold );
}
/* msdos_initialize --
@@ -89,14 +170,37 @@ void msdos_unlock(const rtems_filesystem_mount_table_entry_t *mt_entry)
* RC_OK on success, or -1 if error occured (errno set apropriately).
*
*/
-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 *mount_options )
{
- int rc;
+ int rc;
+ rtems_dosfs_string_options string_opts;
- rc = msdos_initialize_support(mt_entry,
- &msdos_ops,
- &msdos_file_handlers,
- &msdos_dir_handlers);
- return rc;
-}
+
+ if ( NULL == mount_options ) {
+ rc = rtems_dosfs_string_options_init(
+ &string_opts,
+ NULL,
+ msdos_utf8_to_codepage_no_convert,
+ msdos_codepage_to_utf8_no_convert,
+ msdos_utf8_to_utf16_no_convert,
+ msdos_utf16_to_utf8_no_convert,
+ msdos_utf8_normalize_and_fold );
+
+ if ( rc == 0 ) {
+ rc = msdos_initialize_support( mt_entry,
+ &msdos_ops,
+ &msdos_file_handlers,
+ &msdos_dir_handlers,
+ &string_opts );
+ }
+ } else {
+ rc = msdos_initialize_support( mt_entry,
+ &msdos_ops,
+ &msdos_file_handlers,
+ &msdos_dir_handlers,
+ ( (rtems_dosfs_mount_options *) mount_options )->string_opts );
+ }
+
+ return rc;
+}
\ No newline at end of file
diff --git a/cpukit/libfs/src/dosfs/msdos_initsupp.c b/cpukit/libfs/src/dosfs/msdos_initsupp.c
index 0844186..b03cc42 100644
--- a/cpukit/libfs/src/dosfs/msdos_initsupp.c
+++ b/cpukit/libfs/src/dosfs/msdos_initsupp.c
@@ -52,7 +52,8 @@ msdos_initialize_support(
rtems_filesystem_mount_table_entry_t *temp_mt_entry,
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_string_options *string_opts
)
{
int rc = RC_OK;
@@ -68,6 +69,8 @@ msdos_initialize_support(
temp_mt_entry->fs_info = fs_info;
+ fs_info->string_opts = *string_opts;
+
rc = fat_init_volume_info(&fs_info->fat, temp_mt_entry->dev);
if (rc != RC_OK)
{
diff --git a/cpukit/libfs/src/dosfs/msdos_misc.c b/cpukit/libfs/src/dosfs/msdos_misc.c
index a1979b1..bb6cd70 100644
--- a/cpukit/libfs/src/dosfs/msdos_misc.c
+++ b/cpukit/libfs/src/dosfs/msdos_misc.c
@@ -26,6 +26,8 @@
#include <unistd.h>
#include <string.h>
#include <assert.h>
+#include <errno.h>
+#include <inttypes.h>
#include <rtems/libio_.h>
#include "fat.h"
@@ -69,7 +71,7 @@ msdos_is_valid_name_char(const char ch)
return MSDOS_NAME_LONG;
if ((ch == '.') || isalnum((unsigned char)ch) ||
- (strchr("$%'-_@~`!(){}^#&", ch) != NULL))
+ (strchr("$%'-_@~`!(){}^#&", ch) != NULL) || (unsigned char) ch > 127)
return MSDOS_NAME_SHORT;
return MSDOS_NAME_INVALID;
@@ -192,10 +194,15 @@ msdos_name_type(const char *name, int name_len)
*/
#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_string_options *string_opts,
+ const char *lfn,
+ int lfn_len,
+ char *sfn,
+ int sfn_len)
{
msdos_name_type_t type;
int i;
+ ssize_t short_filename_length = sfn_len;
/*
* Fill with spaces. This is how a short directory entry is padded.
@@ -252,7 +259,16 @@ msdos_long_to_short(const char *lfn, int lfn_len, char* sfn, int sfn_len)
return MSDOS_NAME_INVALID;
}
- msdos_filename_unix2dos (lfn, lfn_len, sfn);
+ short_filename_length = msdos_filename_utf8_to_short_name (
+ string_opts,
+ (const uint8_t*)lfn,
+ lfn_len,
+ sfn,
+ short_filename_length,
+ MSDOS_STRING_TYPE_CODEPAGE);
+ 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);
@@ -292,13 +308,15 @@ msdos_find_name(
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->string_opts,
+ 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'
*/
rc = msdos_get_name_node(parent_loc, false, name, name_len, name_type,
@@ -426,7 +444,7 @@ msdos_get_name_node(
/* 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))
return rc;
@@ -542,8 +560,10 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset(
/* 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(
+ &fs_info->string_opts,
+ ".", 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);
if (rc != RC_OK)
@@ -554,8 +574,10 @@ msdos_get_dotdot_dir_info_cluster_num_and_offset(
/* 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(
+ &fs_info->string_opts,
+ "..", 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);
@@ -914,118 +936,270 @@ msdos_dir_is_empty(
return RC_OK;
}
-/* 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.
- *
- * PARAMETERS:
- * mt_entry - mount table entry
- * fat_fd - fat-file descriptor
- * name - NULL or name to find
- * paux - identify a node location on the disk -
- * number of cluster and offset inside the cluster
- * name_dir_entry - node to create/placeholder for found node
- *
- * RETURNS:
- * RC_OK on success, or error code if error occured (errno set
- * appropriately)
- *
- */
#define MSDOS_FIND_PRINT 0
-int msdos_find_name_in_fat_file(
- rtems_filesystem_mount_table_entry_t *mt_entry,
+static int
+msdos_on_entry_found (
+ 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,
+ char *name_dir_entry,
+ char *entry,
fat_dir_pos_t *dir_pos,
- char *name_dir_entry
- )
+ uint32_t *dir_offset,
+ const uint32_t dir_entry,
+ const fat_pos_t *lfn_start
+)
{
- 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);
+ 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;
- fat_dir_pos_init(dir_pos);
+ memcpy(name_dir_entry, entry,
+ MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
+ }
+ }
- lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
+ return rc;
+}
- /*
- * 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;
+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;
- if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
- (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
- bts2rd = fat_fd->fat_file_size;
+ return chars_in_entry * MSDOS_NAME_LFN_BYTES_PER_CHAR;
+ }
else
- bts2rd = fs_info->fat.vol.bpc;
+ return ENOMEM;
+}
- entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
+static ssize_t
+msdos_get_long_name_entry_as_utf8 (
+ rtems_dosfs_string_options *string_opts,
+ const char *entry,
+ const bool is_first_entry,
+ uint8_t *entry_utf8_buf,
+ const size_t buf_size)
+{
+ ssize_t retval = 0;
+ size_t bytes_in_buf = buf_size;
+ 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;
+ if (NULL != string_opts->string_handling.utf16_to_utf8 (
+ string_opts->string_handling_ctx.optional_args,
+ &entry_string[0],
+ bytes_in_buf,
+ &entry_utf8_buf[0],
+ &bytes_in_buf ) ) {
+ retval = bytes_in_buf;
+ }
+ else
+ retval = -1;
+ }
-#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);
+ return retval;
+}
+
+static int
+msdos_compare_entry_against_long_filename (
+ rtems_dosfs_string_options *string_opts,
+ const char *entry,
+ const uint8_t *filename,
+ const size_t filename_size,
+ const bool is_first_entry,
+ bool *is_matching)
+{
+ int retval = 0;
+ ssize_t bytes_read;
+ size_t bytes_in_entry;
+ uint8_t entry_utf8 [MSDOS_ENTRY_LFN_UTF8_BYTES];
+ uint8_t entry_utf8_normalized[( MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
+ size_t bytes_in_entry_normalized = sizeof ( entry_utf8_normalized );
+
+ bytes_read = msdos_get_long_name_entry_as_utf8 (
+ string_opts,
+ entry,
+ is_first_entry,
+ &entry_utf8[0],
+ sizeof (entry_utf8));
+ if (bytes_read >= 0) {
+ bytes_in_entry = bytes_read;
+ if (bytes_in_entry > filename_size)
+ *is_matching = false;
+ else {
+ if (NULL != string_opts->string_handling.utf8_normalize_and_fold (
+ string_opts->string_handling_ctx.optional_args,
+ &entry_utf8[0],
+ bytes_in_entry,
+ &entry_utf8_normalized[0],
+ &bytes_in_entry_normalized)) {
+#if MSDOS_FIND_PRINT > 1
+ printf ( "MSFS:[6] entry_utf8_normalized:%s"
+ "name:%s\n",
+ entry_utf8_normalized,
+ filename );
#endif
+ if ( is_first_entry
+ && bytes_in_entry_normalized != filename_size)
+ *is_matching = false;
+ else if (0 == memcmp ( &entry_utf8_normalized[0],
+ &filename[0],
+ bytes_in_entry_normalized)) {
+ *is_matching = true;
+ }
+ else
+ *is_matching = false;
+ }
+ else
+ retval = -1;
+ }
+ }
+ else
+ retval = -1;
+
+ return retval;
+}
+
+
+static ssize_t
+msdos_file_name_to_short_entry_string (
+ const uint8_t *filename,
+ const size_t filename_size,
+ uint8_t *entry_buf,
+ const size_t entry_buf_size)
+{
+ size_t number_of_bytes = MIN (filename_size, MSDOS_SHORT_NAME_LEN);
+
+ assert (entry_buf != NULL);
+ assert (entry_buf_size >= MSDOS_SHORT_NAME_LEN);
+
+ memcpy (entry_buf, filename, number_of_bytes);
+ if (number_of_bytes < MSDOS_SHORT_NAME_LEN)
+ memset (&entry_buf[number_of_bytes], ' ', MSDOS_SHORT_NAME_LEN - number_of_bytes);
+
+ return MSDOS_SHORT_NAME_LEN;
+}
+
+static int
+msdos_find_file_in_directory (
+ const uint8_t *filename_converted,
+ const size_t filename_converted_size,
+ const msdos_name_type_t name_type,
+ msdos_fs_info_t *fs_info,
+ fat_file_fd_t *fat_fd,
+ const uint32_t bts2rd,
+ const bool create_node,
+ const unsigned int fat_entries,
+ char *name_dir_entry,
+ fat_dir_pos_t *dir_pos,
+ 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 lfn_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 [MSDOS_ENTRY_LFN_UTF8_BYTES];
+ uint8_t entry_utf8_normalized[MSDOS_ENTRY_LFN_UTF8_BYTES];
+ uint8_t *filename_entry_format = &entry_utf8[0];
+ size_t filename_entry_format_size;
+ size_t bytes_in_entry;
+ size_t bytes_in_entry_normalized;
+ bool filename_matched = false;
+
/*
* Scan the directory seeing if the file is present. While
* doing this see if a suitable location can be found to
* 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);
+ printf ("MSFS:[2] dir_offset:%li\n", *dir_offset);
#endif
- if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
+ 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)
{
char* entry = (char*) fs_info->cl_buf + dir_entry;
/*
* 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) ==
MSDOS_THIS_DIR_ENTRY_EMPTY);
@@ -1033,7 +1207,7 @@ int msdos_find_name_in_fat_file(
MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
#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
/*
@@ -1043,10 +1217,10 @@ int msdos_find_name_in_fat_file(
* we are currently not inside an empty series of entries. It
* 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;
}
if (remainder_empty)
@@ -1059,7 +1233,7 @@ int msdos_find_name_in_fat_file(
* directory - return name-not-found
*/
if (!create_node)
- return MSDOS_NAME_NOT_FOUND_ERR;
+ rc = MSDOS_NAME_NOT_FOUND_ERR;
/*
* Lets go and write the directory entries. If we have not found
@@ -1067,13 +1241,14 @@ int msdos_find_name_in_fat_file(
* we may have already found that are just before this entry. If more
* 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;
+ empty_space_found = true;
#if MSDOS_FIND_PRINT
- printf ("MSFS:[3.2] esf:%i esc%i\n", empty_space_found, empty_space_count);
+ printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_space_count );
#endif
}
break;
@@ -1082,17 +1257,17 @@ int msdos_find_name_in_fat_file(
{
if (create_node)
{
- /*
- * Remainder is not empty so is this entry empty ?
- */
- empty_space_count++;
+ /*
+ * Remainder is not empty so is this entry empty ?
+ */
+ (*empty_space_count)++;
- if (empty_space_count == (lfn_entries + 1))
- empty_space_found = true;
+ 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
}
else
@@ -1105,8 +1280,8 @@ int msdos_find_name_in_fat_file(
*/
if (create_node && !empty_space_found)
{
- empty_space_entry = 0;
- empty_space_count = 0;
+ *empty_space_entry = 0;
+ *empty_space_count = 0;
}
/*
@@ -1116,9 +1291,7 @@ int msdos_find_name_in_fat_file(
if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
MSDOS_ATTR_LFN)
{
- char* p;
int o;
- int i;
#if MSDOS_FIND_PRINT
printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
lfn_start.cln == FAT_FILE_SHORT_NAME ? 'f' : 't',
@@ -1148,21 +1321,21 @@ int msdos_find_name_in_fat_file(
* characters in the entry so this is check further
* 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;
/*
* 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
}
@@ -1182,60 +1355,25 @@ int msdos_find_name_in_fat_file(
lfn_start.cln = FAT_FILE_SHORT_NAME;
continue;
}
-
- 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;
- }
+ lfn_entry--;
+ o = lfn_entry * MSDOS_LFN_LEN_PER_ENTRY;
- if (((o + i) >= name_len) || (*p != name[o + i]))
- {
- lfn_start.cln = FAT_FILE_SHORT_NAME;
- break;
- }
+ rc = msdos_compare_entry_against_long_filename (
+ &fs_info->string_opts,
+ entry,
+ &filename_converted[o],
+ filename_converted_size - o,
+ (lfn_entry + 1) == fat_entries,
+ &lfn_matched);
- switch (i)
- {
- case 4:
- p += 5;
- break;
- case 10:
- p += 4;
- break;
- default:
- p += 2;
- break;
- }
+ if (rc == 0
+ && (! lfn_matched)) {
+ lfn_start.cln = FAT_FILE_SHORT_NAME;
}
-
- 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
@@ -1260,80 +1398,133 @@ int msdos_find_name_in_fat_file(
if (lfn_entry || (lfn_checksum != cs))
lfn_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, lfn_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
lfn_matched, lfn_entry, lfn_checksum, cs);
#endif
- }
-
- /*
- * 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;
+ } else {
+ bytes_in_entry = MSDOS_SHORT_NAME_LEN;
+ bytes_in_entry_normalized = sizeof (entry_utf8_normalized);
+ if (NULL != fs_info->string_opts.string_handling.codepage_to_utf8 (
+ fs_info->string_opts.string_handling_ctx.optional_args,
+ MSDOS_DIR_NAME (entry),
+ (size_t)MSDOS_SHORT_NAME_LEN,
+ &entry_utf8[0],
+ &bytes_in_entry)) {
+ if (NULL != fs_info->string_opts.string_handling.utf8_normalize_and_fold (
+ fs_info->string_opts.string_handling_ctx.optional_args,
+ &entry_utf8[0],
+ bytes_in_entry,
+ &entry_utf8_normalized[0],
+ &bytes_in_entry_normalized) ) {
+ filename_entry_format_size = msdos_file_name_to_short_entry_string (
+ filename_converted,
+ filename_converted_size,
+ filename_entry_format,
+ MSDOS_ENTRY_LFN_UTF8_BYTES);
+ /*
+ * 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 ( bytes_in_entry_normalized ==
+ filename_entry_format_size
+ && lfn_start.cln == FAT_FILE_SHORT_NAME
+ && (0 == memcmp (entry_utf8_normalized,
+ filename_entry_format,
+ bytes_in_entry_normalized))) {
+ 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;
+ lfn_matched = false;
+ }
+ }
+ else
+ rc = -1;
}
-
- 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;
+ else
+ rc = -1;
}
-
- lfn_start.cln = FAT_FILE_SHORT_NAME;
- lfn_matched = false;
}
}
}
- if (remainder_empty)
+ if (filename_matched || remainder_empty)
break;
- dir_offset++;
+ (*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 ( ! 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:%ld esc:%ld eso:%ld ese:%ld\n",
- dir_offset, empty_space_count, empty_space_offset, empty_space_entry);
+ 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;
/*
* If a long file name calculate the checksum of the short file name
@@ -1341,15 +1532,14 @@ int msdos_find_name_in_fat_file(
* file name to the slot of the SFN entry. This will mean no clashes
* 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);
int i;
@@ -1392,53 +1582,53 @@ int msdos_find_name_in_fat_file(
/*
* The one more is the short entry.
*/
- while (lfn_entry < (lfn_entries + 1))
+ while (lfn_entry < (fat_entries + 1))
{
int length = 0;
if (read_cluster)
{
- uint32_t new_length;
+ uint32_t new_length;
#if MSDOS_FIND_PRINT
- printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
+ 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);
+ 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 (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);
+ 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);
+ ret = fat_file_extend (&fs_info->fat, fat_fd, false,
+ empty_space_offset * bts2rd, &new_length);
- if (ret != RC_OK)
- return ret;
+ if (ret != RC_OK)
+ return ret;
#if MSDOS_FIND_PRINT
- printf ("MSFS:[9.3] extended: %d <-> %d\n", new_length, empty_space_offset * bts2rd);
+ 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);
+ if (new_length != (empty_space_offset * bts2rd))
+ rtems_set_errno_and_return_minus_one(EIO);
- memset(fs_info->cl_buf, 0, bts2rd);
+ 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);
+ 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);
+ 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);
- }
+ if (bytes_written == -1)
+ return -1;
+ else if (bytes_written != bts2rd)
+ rtems_set_errno_and_return_minus_one(EIO);
+ }
}
#if MSDOS_FIND_PRINT
@@ -1466,24 +1656,24 @@ int msdos_find_name_in_fat_file(
/*
* 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;
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;
}
dir_pos->lname.cln = lfn_start.cln;
@@ -1503,8 +1693,8 @@ int msdos_find_name_in_fat_file(
*/
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;
}
/*
@@ -1515,14 +1705,17 @@ int msdos_find_name_in_fat_file(
*MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
p = entry + 1;
- n = name + (lfn_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY;
+ n = name_converted + (fat_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR;
- for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++)
+#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
{
@@ -1530,6 +1723,10 @@ int msdos_find_name_in_fat_file(
p [1] = fill;
fill = 0xff;
}
+ n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
+#if MSDOS_FIND_PRINT
+ printf ( "'%c''%c'", *p, *(p+1) );
+#endif
switch (i)
{
@@ -1544,29 +1741,184 @@ int msdos_find_name_in_fat_file(
break;
}
}
-
- *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;
*MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
}
- 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);
empty_space_offset++;
empty_space_entry = 0;
read_cluster = true;
}
+ 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;
+ size_t name_converted_len;
+ 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;
+
+ 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:
+ memset (&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0], 0,
+ MSDOS_SHORT_NAME_LEN);
+ name_converted_len = msdos_filename_utf8_to_short_name (
+ &fs_info->string_opts,
+ name_utf8,
+ name_utf8_len,
+ (char*)&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0],
+ MSDOS_SHORT_NAME_LEN,
+ MSDOS_STRING_TYPE_UTF8);
+ if (name_converted_len > 0) {
+ fat_entries = 0;
+ }
+ else
+ retval = -1;
+ break;
+ case MSDOS_NAME_LONG:
+ memset (&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0], 0,
+ MSDOS_NAME_MAX_LFN_BYTES);
+ name_converted_len = msdos_filename_utf8_to_long_name_for_compare (
+ &fs_info->string_opts,
+ name_utf8,
+ name_utf8_len/* +1*/,
+ &fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0],
+ MSDOS_NAME_MAX_LFN_BYTES);
+ if (name_converted_len > 0) {
+ fat_entries = (name_converted_len -1
+ + MSDOS_LFN_LEN_PER_ENTRY) / MSDOS_LFN_LEN_PER_ENTRY;
+ }
+ else
+ retval = -1;
+ break;
+ case MSDOS_NAME_INVALID:
+ default:
+ errno = EINVAL;
+ retval = -1;
+ break;
+ }
+ /* See if the file/directory does already exist */
+ retval = msdos_find_file_in_directory (
+ &fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0],
+ name_converted_len,
+ 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:
+ memset (&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0], 0,
+ MSDOS_SHORT_NAME_LEN);
+ name_converted_len = msdos_filename_utf8_to_short_name (
+ &fs_info->string_opts,
+ name_utf8,
+ name_utf8_len,
+ (char*)&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0],
+ MSDOS_SHORT_NAME_LEN,
+ MSDOS_STRING_TYPE_CODEPAGE);
+ if (name_converted_len > 0 ) {
+ fat_entries = 0;
+ }
+ else
+ retval = -1;
+ break;
+ case MSDOS_NAME_LONG:
+ memset (&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0], 0,
+ MSDOS_NAME_MAX_LFN_BYTES);
+ name_converted_len = msdos_filename_utf8_to_long_name_for_save (
+ &fs_info->string_opts,
+ name_utf8,
+ name_utf8_len,
+ (uint16_t*)&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0],
+ MIN (MSDOS_NAME_MAX_LFN_BYTES,
+ name_utf8_len * MSDOS_NAME_LFN_BYTES_PER_CHAR));
+ if (name_converted_len > 0) {
+ name_converted_len = name_converted_len / MSDOS_NAME_LFN_BYTES_PER_CHAR;
+ fat_entries = (name_converted_len -1
+ + MSDOS_LFN_LEN_PER_ENTRY) / MSDOS_LFN_LEN_PER_ENTRY;
+
+ }
+ else
+ retval = -1;
+ break;
+ case MSDOS_NAME_INVALID:
+ default:
+ errno = EINVAL;
+ retval = -1;
+ break;
+ }
+ retval = msdos_add_file (
+ (const char*)&fs_info->string_opts.string_handling_ctx.file_name_scratch_buf[0],
+ 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 0;
+ return retval;
}
+
/* msdos_find_node_by_cluster_num_in_fat_file --
* Find node with specified number of cluster in fat-file.
*
diff --git a/cpukit/libfs/src/dosfs/msdos_string_handling_no_convert.c b/cpukit/libfs/src/dosfs/msdos_string_handling_no_convert.c
new file mode 100644
index 0000000..60e8fc7
--- /dev/null
+++ b/cpukit/libfs/src/dosfs/msdos_string_handling_no_convert.c
@@ -0,0 +1,166 @@
+/**
+ * @file msdos_string_handling_no_convert.c
+ *
+ * @ingroup libfs
+ *
+ * @brief Default- mostly stubbed implementations of string conversion methods
+ */
+
+/*
+ * Copyright (c) 2012, 2013 embedded brains GmbH. All rights reserved.
+ *
+ * embedded brains GmbH
+ * Dornierstr. 4
+ * 82178 Puchheim
+ * Germany
+ * <rtems at 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 <rtems/dosfs.h>
+#include "fat.h"
+
+char *msdos_utf8_to_codepage_no_convert(
+ void *string_arg,
+ const uint8_t *str,
+ const size_t strsize,
+ char *buffer,
+ size_t *bufsize )
+{
+ char *retval = NULL;
+ size_t bytes_to_copy = MIN( strsize, *bufsize );
+
+
+ (void) string_arg;
+
+ if ( str != NULL
+ && buffer != NULL ) {
+ memcpy( buffer, str, bytes_to_copy );
+
+ *bufsize = bytes_to_copy;
+ retval = buffer;
+ } else
+ errno = EINVAL;
+
+ return retval;
+}
+
+uint8_t *msdos_codepage_to_utf8_no_convert(
+ void *string_arg,
+ const char *str,
+ const size_t strsize,
+ uint8_t *buffer,
+ size_t *bufsize )
+{
+ uint8_t *retval = NULL;
+ size_t bytes_to_copy = MIN( strsize, *bufsize );
+
+
+ (void) string_arg;
+
+ if ( str != NULL
+ && buffer != NULL ) {
+ memcpy( buffer, str, bytes_to_copy );
+
+ *bufsize = bytes_to_copy;
+ retval = buffer;
+ } else
+ errno = EINVAL;
+
+ return retval;
+}
+
+uint16_t *msdos_utf8_to_utf16_no_convert(
+ void *string_arg,
+ const uint8_t *str,
+ const size_t strsize,
+ uint16_t *buffer,
+ size_t *bufsize )
+{
+ uint16_t *retval = NULL;
+ size_t bytes_to_copy = MIN( strsize, *bufsize );
+ unsigned int index;
+ uint16_t utf16_char;
+
+
+ (void) string_arg;
+
+ if ( str != NULL
+ && buffer != NULL ) {
+ for ( index = 0; index < bytes_to_copy; ++index ) {
+ utf16_char = str[index] << 8;
+ buffer[index] = 0xff00 & utf16_char;
+ }
+
+ *bufsize = bytes_to_copy * 2;
+ retval = buffer;
+ } else
+ errno = EINVAL;
+
+ return retval;
+}
+
+uint8_t *msdos_utf16_to_utf8_no_convert(
+ void *string_arg,
+ const uint16_t *str,
+ const size_t strsize,
+ uint8_t *buffer,
+ size_t *bufsize )
+{
+ uint8_t *retval = NULL;
+ size_t bytes_to_copy = MIN( strsize / 2, *bufsize );
+ unsigned int index;
+
+
+ (void) string_arg;
+
+ if ( str != NULL
+ && buffer != NULL ) {
+ for ( index = 0; index < bytes_to_copy; ++index ) {
+ buffer[index] = ( 0xff00 & str[index] ) >> 8;
+ }
+
+ *bufsize = bytes_to_copy;
+ retval = buffer;
+ } else
+ errno = EINVAL;
+
+ return retval;
+}
+
+uint8_t *msdos_utf8_normalize_and_fold(
+ void *string_arg,
+ const uint8_t *str,
+ const size_t strsize,
+ uint8_t *buffer,
+ size_t *bufsize )
+{
+ uint8_t *retval = NULL;
+ size_t bytes_to_copy = MIN( strsize, *bufsize );
+ unsigned int i;
+
+
+ (void) string_arg;
+
+ if ( str != NULL
+ && buffer != NULL ) {
+ for ( i = 0; i < bytes_to_copy; ++i ) {
+ if ( isalpha( str[i] ) )
+ buffer[i] = tolower( str[i] );
+ else
+ buffer[i] = str[i];
+ }
+
+ *bufsize = bytes_to_copy;
+ retval = buffer;
+ } else
+ errno = EINVAL;
+
+ return retval;
+}
--
1.7.10.4
More information about the devel
mailing list