dosfs: UTF-8 Support: UI, backwards compatibility

User interface and backwards compatibility for UTF-8 support in the FAT
file system.  Purpose of UTF-8 support is to permit file names and
directory names with characters from all kinds of languages (Czech,
Chinese, Arabian, Hebrew, Korean, ...).  This commit does not yet
support multibyte characters. It only contains the user interface and
the backwards compatibility.
This commit is contained in:
Ralf Kirchner
2013-05-22 12:16:18 +02:00
committed by Sebastian Huber
parent 8bed60314e
commit d2e0bb36e3
11 changed files with 1785 additions and 564 deletions

View File

@@ -81,6 +81,7 @@ libdosfs_a_SOURCES += src/dosfs/msdos_create.c src/dosfs/msdos_dir.c \
src/dosfs/msdos_initsupp.c src/dosfs/msdos_misc.c \
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
endif

View File

@@ -1,15 +1,18 @@
/**
* @file rtems/dosfs.h
* @file
*
* @brief Application Interface to MSDOS Filesystem
* @brief Application Interface to FAT Filesystem
*
* @ingroup rtems_msdos_format
* @ingroup DOSFS
*/
/*
* 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
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
@@ -25,6 +28,170 @@
extern "C" {
#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.
*
@@ -32,16 +199,27 @@ extern "C" {
*/
#define RTEMS_DOSFS_SEMAPHORES_PER_INSTANCE 1
int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
const void *data);
/**
* @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;
/**
* @defgroup rtems_msdos_format DOSFS Support
* @brief Allocates and initializes a default converter.
*
* @ingroup FileSystemTypesAndMount
* @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)
#define MSDOS_FMT_INFO_LEVEL_INFO (1)
@@ -131,6 +309,9 @@ int msdos_format (
/** @} */
int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
const void *data);
#ifdef __cplusplus
}
#endif

View File

@@ -10,6 +10,9 @@
* 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
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
@@ -20,6 +23,7 @@
#include <rtems.h>
#include <rtems/libio_.h>
#include <rtems/dosfs.h>
#include "fat.h"
#include "fat_file.h"
@@ -67,6 +71,8 @@ typedef struct msdos_fs_info_s
* just placeholder
* for anything
*/
rtems_dosfs_convert_control *converter;
} msdos_fs_info_t;
/* a set of routines that handle the nodes which are directories */
@@ -183,6 +189,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 +198,20 @@ 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_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 */
extern const char *const MSDOS_DOTDOT_NAME; /* ".", padded to MSDOS_NAME chars */
@@ -309,7 +328,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_convert_control *converter
);
int msdos_file_close(rtems_libio_t *iop /* IN */);
@@ -387,10 +407,52 @@ 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,
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(
unsigned int tsp, uint16_t *ddp,
@@ -430,7 +492,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,

View File

@@ -22,18 +22,38 @@
* $NetBSD: msdosfs_conv.c,v 1.10 1994/12/27 18:36:24 mycroft Exp $
*
* October 1992
*
* Modifications to support UTF-8 in the file system are
* Copyright (c) 2013 embedded brains GmbH.
*/
#if HAVE_CONFIG_H
#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 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
/*
* Days in each month in a regular year.
*/
@@ -174,150 +194,485 @@ 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, 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)
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 char_num = CF_LE_W( utf16_character );
/*
* Fill the dos filename string with blanks. These are DOS's pad
* characters.
*/
for (i = 0; i <= 10; i++)
dn[i] = ' ';
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;
/*
* 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;
}
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;
/*
* 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 start of a file name.
* Remove any dots from the end of a file name.
*/
while (unlen && (*un == '.')) {
un++;
unlen--;
}
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;
}
/*
* 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;
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;
}

View File

@@ -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;
}

View File

@@ -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->converter,
name, name_len,
MSDOS_DIR_NAME(short_node),
MSDOS_NAME_MAX);
if (name_type == MSDOS_NAME_INVALID) {

View File

@@ -9,6 +9,9 @@
* 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
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
@@ -33,74 +36,7 @@
#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 --
* This routine will read the next directory entry based on the directory
@@ -128,11 +64,18 @@ ssize_t
msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
{
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;
uint32_t cmpltd = 0;
@@ -142,6 +85,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 +112,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 +128,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 +158,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 +185,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 +209,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 +219,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],
buf_size - offset_lfn,
is_first_entry
);
}
else
{
@@ -344,9 +274,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 +290,20 @@ msdos_dir_read(rtems_libio_t *iop, void *buffer, size_t count)
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;
}
}
if (lfn_start == FAT_FILE_SHORT_NAME)
@@ -368,25 +313,37 @@ 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 */
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;
}
}
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;
}
}
}

View File

@@ -47,13 +47,15 @@ msdos_shut_down(rtems_filesystem_mount_table_entry_t *temp_mt_entry)
{
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);
fat_shutdown_drive(&fs_info->fat);
rtems_semaphore_delete(fs_info->vol_sema);
(*converter->handler->destroy)( converter );
free(fs_info->cl_buf);
free(temp_mt_entry->fs_info);
}

View File

@@ -12,6 +12,9 @@
* 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
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
@@ -89,14 +92,32 @@ 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 *data
)
{
int rc;
int rc = 0;
const rtems_dosfs_mount_options *mount_options = data;
rtems_dosfs_convert_control *converter;
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;
}
rc = msdos_initialize_support(mt_entry,
&msdos_ops,
&msdos_file_handlers,
&msdos_dir_handlers);
return rc;
}

View File

@@ -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_convert_control *converter
)
{
int rc = RC_OK;
@@ -68,6 +69,8 @@ msdos_initialize_support(
temp_mt_entry->fs_info = fs_info;
fs_info->converter = converter;
rc = fat_init_volume_info(&fs_info->fat, temp_mt_entry->dev);
if (rc != RC_OK)
{

File diff suppressed because it is too large Load Diff