Changeset d2e0bb3 in rtems


Ignore:
Timestamp:
May 22, 2013, 10:16:18 AM (7 years ago)
Author:
Ralf Kirchner <ralf.kirchner@…>
Branches:
4.11, master
Children:
ccd212e
Parents:
8bed603
git-author:
Ralf Kirchner <ralf.kirchner@…> (05/22/13 10:16:18)
git-committer:
Sebastian Huber <sebastian.huber@…> (06/03/13 15:28:40)
Message:

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.

Location:
cpukit/libfs
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • cpukit/libfs/Makefile.am

    r8bed603 rd2e0bb3  
    8282    src/dosfs/msdos_mknod.c src/dosfs/msdos_node_type.c \
    8383    src/dosfs/msdos_rmnod.c src/dosfs/msdos_statvfs.c \
     84    src/dosfs/msdos_conv_default.c \
    8485    src/dosfs/msdos_conv.c src/dosfs/msdos.h src/dosfs/msdos_format.c \
    8586    src/dosfs/dosfs.h src/dosfs/msdos_rename.c
  • cpukit/libfs/src/dosfs/dosfs.h

    r8bed603 rd2e0bb3  
    11/**
    2  * @file rtems/dosfs.h
    3  *
    4  * @brief Application Interface to MSDOS Filesystem
    5  *
    6  * @ingroup rtems_msdos_format
     2 * @file
     3 *
     4 * @brief Application Interface to FAT Filesystem
     5 *
     6 * @ingroup DOSFS
    77 */
    88
     
    1111 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
    1212 *
     13 *  Modifications to support UTF-8 in the file system are
     14 *  Copyright (c) 2013 embedded brains GmbH.
     15 *
    1316 *  The license and distribution terms for this file may be
    1417 *  found in the file LICENSE in this distribution or at
     
    2629#endif
    2730
     31typedef struct rtems_dosfs_convert_control rtems_dosfs_convert_control;
     32
     33/**
     34 * @brief Converts from UTF-8 into a specific code page.
     35 *
     36 * @param[in/out] self The convert control.
     37 * @param[in] src A well-formed UTF-8 string to be converted.
     38 * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
     39 * @param[out] dst The address the converted string will get copied to.
     40 * @param[in/out] dst_size The size of the buffer in bytes respectively the
     41 * number of bytes written to the buffer.
     42 *
     43 * @retval 0 Successful operation.
     44 * @retval EINVAL Conversion was successful, but is not reversible.
     45 * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
     46 */
     47typedef int (*rtems_dosfs_utf8_to_codepage)(
     48  rtems_dosfs_convert_control *self,
     49  const uint8_t               *src,
     50  size_t                       src_size,
     51  char                        *dst,
     52  size_t                      *dst_size
     53);
     54
     55/**
     56 * @brief Converts from a specific code page into UTF-8
     57 *
     58 * @param[in/out] self The convert control.
     59 * @param[in] src A well-formed string in code page format.
     60 * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
     61 * @param[out] dst The address the converted string will get copied to.
     62 * @param[in/out] dst_size The size of the buffer in bytes respectively the
     63 * number of bytes written to the buffer.
     64 *
     65 * @retval 0 Successful operation.
     66 * @retval EINVAL Conversion was successful, but is not reversible.
     67 * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
     68 */
     69typedef int (*rtems_dosfs_codepage_to_utf8)(
     70  rtems_dosfs_convert_control *self,
     71  const char                  *src,
     72  size_t                       src_size,
     73  uint8_t                     *dst,
     74  size_t                      *dst_size
     75);
     76
     77/**
     78 * @brief Converts from UTF-8 to UTF-16
     79 *
     80 * @param[in/out] self The convert control.
     81 * @param[in] src A well-formed UTF-8 string to be converted.
     82 * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
     83 * @param[out] dst The address the converted string will get copied to
     84 * @param[in/out] dst_size The size of the buffer in bytes respectively the
     85 * number of bytes written to the buffer.
     86 *
     87 * @retval 0 Successful operation.
     88 * @retval EINVAL Conversion was successful, but is not reversible.
     89 * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
     90 */
     91typedef int (*rtems_dosfs_utf8_to_utf16)(
     92  rtems_dosfs_convert_control *self,
     93  const uint8_t               *src,
     94  size_t                       src_size,
     95  uint16_t                    *dst,
     96  size_t                      *dst_size
     97);
     98
     99/**
     100 * @brief Converts from UTF-16 to UTF-8.
     101 *
     102 * @param[in/out] self The convert control.
     103 * @param[in] src A well-formed UTF-16 string to be converted.
     104 * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
     105 * @param[out] dst The address the converted string will get copied to.
     106 * @param[in/out] dst_size The size of the buffer in bytes respectively the
     107 * number of bytes written to the buffer
     108 *
     109 * @retval 0 Successful operation.
     110 * @retval EINVAL Conversion was successful, but is not reversible.
     111 * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
     112 */
     113typedef int (*rtems_dosfs_utf16_to_utf8)(
     114  rtems_dosfs_convert_control *self,
     115  const uint16_t              *src,
     116  size_t                       src_size,
     117  uint8_t                     *dst,
     118  size_t                      *dst_size
     119);
     120
     121/**
     122 * @brief Converts from UTF-8 to Normalized Form Canonical Decomposition.
     123 *
     124 * Does canonical decomposition of the UTF-8 string and in addition
     125 * also converts upper case alphabetic characters to lower case characters
     126 *
     127 * @param[in/out] self The convert control.
     128 * @param[in] src A well-formed UTF-8 string to be normalized and fold.
     129 * @param[in] src_size The size of the string in bytes (inludes '\0' if any).
     130 * @param[out] dst The address the normalized and fold string will get
     131 * copied to.
     132 * @param[in/out] dst_size The size of the buffer in bytes respectively the
     133 * number of bytes written to the buffer.
     134 *
     135 * @retval 0 Successful operation.
     136 * @retval EINVAL Conversion failed.
     137 * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
     138 * @retval EOVERFLOW Conversion failed.
     139 * @retval ENOENT Conversion failed.
     140 */
     141typedef int (*rtems_dosfs_utf8_normalize_and_fold)(
     142  rtems_dosfs_convert_control *self,
     143  const uint8_t               *src,
     144  size_t                       src_size,
     145  uint8_t                     *dst,
     146  size_t                      *dst_size
     147);
     148
     149/**
     150 * @brief Destroys a convert control structure.
     151 *
     152 * @param[in/out] self The convert control for destruction.
     153 */
     154typedef void (*rtems_dosfs_convert_destroy)(
     155  rtems_dosfs_convert_control *self
     156);
     157
     158/**
     159 * @brief FAT filesystem convert handler.
     160 */
     161typedef struct {
     162  rtems_dosfs_utf8_to_codepage        utf8_to_codepage;
     163  rtems_dosfs_codepage_to_utf8        codepage_to_utf8;
     164  rtems_dosfs_utf8_to_utf16           utf8_to_utf16;
     165  rtems_dosfs_utf16_to_utf8           utf16_to_utf8;
     166  rtems_dosfs_utf8_normalize_and_fold utf8_normalize_and_fold;
     167  rtems_dosfs_convert_destroy         destroy;
     168} rtems_dosfs_convert_handler;
     169
     170typedef struct {
     171  void   *data;
     172  size_t  size;
     173} rtems_dosfs_buffer;
     174
     175/**
     176 * @brief FAT filesystem convert control.
     177 *
     178 * Short file names are stored in the code page format.  Long file names are
     179 * stored as little-endian UTF-16.  The convert control determines the format
     180 * conversions to and from the POSIX file name strings.
     181 */
     182struct rtems_dosfs_convert_control {
     183  const rtems_dosfs_convert_handler *handler;
     184  rtems_dosfs_buffer                 buffer;
     185};
     186
     187/**
     188 * @defgroup DOSFS FAT Filesystem Support
     189 *
     190 * @ingroup FileSystemTypesAndMount
     191 *
     192 * @{
     193 */
     194
    28195/**
    29196 * @brief Semaphore count per FAT filesystem instance.
     
    33200#define RTEMS_DOSFS_SEMAPHORES_PER_INSTANCE 1
    34201
    35 int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
    36                            const void                           *data);
    37 
    38 /**
    39  * @defgroup rtems_msdos_format DOSFS Support
    40  *
    41  * @ingroup FileSystemTypesAndMount
    42  *
    43  */
    44 /**@{**/
     202/**
     203 * @brief FAT filesystem mount options.
     204 */
     205typedef struct {
     206  /**
     207   * @brief Converter implementation for new filesystem instance.
     208   *
     209   * @see rtems_dosfs_create_default_converter().
     210   */
     211  rtems_dosfs_convert_control *converter;
     212} rtems_dosfs_mount_options;
     213
     214/**
     215 * @brief Allocates and initializes a default converter.
     216 *
     217 * @retval NULL Something failed.
     218 * @retval other Pointer to initialized converter.
     219 *
     220 * @see rtems_dosfs_mount_options and mount().
     221 */
     222rtems_dosfs_convert_control *rtems_dosfs_create_default_converter(void);
    45223
    46224#define MSDOS_FMT_INFO_LEVEL_NONE   (0)
     
    132310/** @} */
    133311
     312int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
     313                           const void                           *data);
     314
    134315#ifdef __cplusplus
    135316}
  • cpukit/libfs/src/dosfs/msdos.h

    r8bed603 rd2e0bb3  
    1010 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
    1111 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
     12 *
     13 *  Modifications to support UTF-8 in the file system are
     14 *  Copyright (c) 2013 embedded brains GmbH.
    1215 *
    1316 *  The license and distribution terms for this file may be
     
    2124#include <rtems.h>
    2225#include <rtems/libio_.h>
     26#include <rtems/dosfs.h>
    2327
    2428#include "fat.h"
     
    6872                                                            * for anything
    6973                                                            */
     74
     75    rtems_dosfs_convert_control      *converter;
    7076} msdos_fs_info_t;
    7177
     
    184190 *  Macros for names parsing and formatting
    185191 */
     192#define MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR  4
     193#define MSDOS_NAME_MIN_UTF8_BYTES_PER_CHAR  1
    186194
    187195#define MSDOS_SHORT_BASE_LEN             8  /* 8 characters */
     
    191199#define MSDOS_NAME_MAX_LNF_LEN           (255)
    192200#define MSDOS_NAME_MAX                   MSDOS_SHORT_NAME_LEN
     201#define MSDOS_NAME_MAX_UTF8_SFN_BYTES    (MSDOS_NAME_MAX *\
     202                                         MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
    193203#define MSDOS_NAME_MAX_WITH_DOT          (MSDOS_NAME_MAX + 1)
     204#define MSDOS_SFN_MAX_WITH_DOT_UTF8_BYTES (MSDOS_NAME_MAX_WITH_DOT *\
     205                                           MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
    194206#define MSDOS_NAME_MAX_LFN_WITH_DOT      (260)
    195207
     208#define MSDOS_NAME_LFN_BYTES_PER_CHAR    (2)
     209#define MSDOS_NAME_MAX_LFN_BYTES         (MSDOS_NAME_MAX_LFN_WITH_DOT *\
     210                                          MSDOS_NAME_LFN_BYTES_PER_CHAR)
     211#define MSDOS_NAME_MAX_UTF8_LFN_BYTES    (MSDOS_NAME_MAX_LFN_WITH_DOT *\
     212                                          MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
     213#define MSDOS_ENTRY_LFN_UTF8_BYTES       (MSDOS_LFN_LEN_PER_ENTRY *\
     214                                          MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
    196215
    197216extern const char *const MSDOS_DOT_NAME;    /* ".", padded to MSDOS_NAME chars */
     
    310329  const rtems_filesystem_operations_table *op_table,
    311330  const rtems_filesystem_file_handlers_r  *file_handlers,
    312   const rtems_filesystem_file_handlers_r  *directory_handlers
     331  const rtems_filesystem_file_handlers_r  *directory_handlers,
     332  rtems_dosfs_convert_control             *converter
    313333);
    314334
     
    388408int msdos_dir_info_remove(rtems_filesystem_location_info_t *pathloc);
    389409
    390 msdos_name_type_t msdos_long_to_short(const char *lfn, int lfn_len,
     410ssize_t
     411msdos_format_dirent_with_dot(char *dst,const char *src);
     412
     413msdos_name_type_t msdos_long_to_short(rtems_dosfs_convert_control *converter,
     414                                      const char *lfn, int lfn_len,
    391415                                      char* sfn, int sfn_len);
    392416
    393 int msdos_filename_unix2dos(const char *un, int unlen, char *dn);
     417ssize_t
     418msdos_filename_utf8_to_short_name_for_compare (
     419    rtems_dosfs_convert_control     *converter,
     420    const uint8_t                   *utf8_name,
     421    const size_t                     utf8_name_size,
     422    void                            *short_name,
     423    const size_t                     short_name_size);
     424
     425ssize_t
     426msdos_filename_utf8_to_short_name_for_save (
     427    rtems_dosfs_convert_control     *converter,
     428    const uint8_t                   *utf8_name,
     429    const size_t                     utf8_name_size,
     430    void                            *short_name,
     431    const size_t                     short_name_size);
     432
     433ssize_t
     434msdos_filename_utf8_to_long_name_for_compare (
     435    rtems_dosfs_convert_control     *converter,
     436    const uint8_t                   *utf8_name,
     437    const size_t                     utf8_name_size,
     438    uint8_t                         *long_name,
     439    const size_t                     long_name_size);
     440
     441ssize_t
     442msdos_filename_utf8_to_long_name_for_save (
     443    rtems_dosfs_convert_control     *converter,
     444    const uint8_t                   *utf8_name,
     445    const size_t                     utf8_name_size,
     446    uint16_t                        *long_name,
     447    const size_t                     long_name_size);
     448
     449ssize_t
     450msdos_get_utf16_string_from_long_entry (
     451  const char                 *entry,
     452  uint16_t                   *entry_string_buf,
     453  const size_t                buf_size,
     454  bool                        is_first_entry
     455);
    394456
    395457void msdos_date_unix2dos(
     
    431493    fat_file_fd_t                        *fat_fd,
    432494    bool                                  create_node,
    433     const char                           *name,
     495    const uint8_t                        *name_utf8,
    434496    int                                   name_len,
    435497    msdos_name_type_t                     name_type,
  • cpukit/libfs/src/dosfs/msdos_conv.c

    r8bed603 rd2e0bb3  
    2323 *
    2424 * October 1992
     25 *
     26 * Modifications to support UTF-8 in the file system are
     27 * Copyright (c) 2013 embedded brains GmbH.
    2528 */
    2629
     
    2932#endif
    3033
     34#include <ctype.h>
    3135#include <rtems.h>
    3236#include "msdos.h"
     
    3438/* #define SECONDSPERDAY (24 * 60 * 60) */
    3539#define SECONDSPERDAY ((uint32_t) 86400)
     40
     41#define UTF8_MAX_CHAR_SIZE    4
     42#define UTF8_NULL             0x00
     43#define UTF8_NULL_SIZE        1
     44#define UTF8_BLANK            0x20
     45#define UTF8_BLANK_SIZE       1
     46#define UTF8_FULL_STOP        0x2e
     47#define UTF8_FULL_STOP_SIZE   1
     48
     49#define UTF16_MAX_CHAR_SIZE   4
     50#define UTF16_NULL            CT_LE_W( 0x0000 )
     51#define UTF16_NULL_SIZE       2
     52#define UTF16_BLANK           CT_LE_W( 0x0020 )
     53#define UTF16_BLANK_SIZE      2
     54#define UTF16_FULL_STOP       CT_LE_W( 0x002e )
     55#define UTF16_FULL_STOP_SIZE  2
    3656
    3757/*
     
    175195}
    176196
    177 static const uint8_t msdos_map[] = {
     197
     198static const uint8_t codepage_valid_char_map[] = {
    178199    0,    0,    0,    0,    0,    0,    0,    0,    /* 00-07 */
    179200    0,    0,    0,    0,    0,    0,    0,    0,    /* 08-0f */
    180201    0,    0,    0,    0,    0,    0,    0,    0,    /* 10-17 */
    181202    0,    0,    0,    0,    0,    0,    0,    0,    /* 18-1f */
    182     0,    '!',  0,    '#',  '$',  '%',  '&',  '\'', /* 20-27 */
    183     '(',  ')',  0,    '+',  0,    '-',  0,    0,    /* 28-2f */
    184     '0',  '1',  '2',  '3',  '4',  '5',  '6',  '7',  /* 30-37 */
    185     '8',  '9',  0,    0,    0,    0,    0,    0,    /* 38-3f */
    186     '@',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 40-47 */
    187     'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  /* 48-4f */
    188     'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  /* 50-57 */
    189     'X',  'Y',  'Z',  0,    0,    0,    '^',  '_',  /* 58-5f */
    190     '`',  'A',  'B',  'C',  'D',  'E',  'F',  'G',  /* 60-67 */
    191     'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',  /* 68-6f */
    192     'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  /* 70-77 */
    193     'X',  'Y',  'Z',  '{',  0,    '}',  '~',  0,    /* 78-7f */
    194     0,    0,    0,    0,    0,    0,    0,    0,    /* 80-87 */
    195     0,    0,    0,    0,    0,    0,    0,    0,    /* 88-8f */
    196     0,    0,    0,    0,    0,    0,    0,    0,    /* 90-97 */
    197     0,    0,    0,    0,    0,    0,    0,    0,    /* 98-9f */
    198     0,    0xad, 0xbd, 0x9c, 0xcf, 0xbe, 0xdd, 0xf5, /* a0-a7 */
    199     0xf9, 0xb8, 0xa6, 0xae, 0xaa, 0xf0, 0xa9, 0xee, /* a8-af */
    200     0xf8, 0xf1, 0xfd, 0xfc, 0xef, 0xe6, 0xf4, 0xfa, /* b0-b7 */
    201     0xf7, 0xfb, 0xa7, 0xaf, 0xac, 0xab, 0xf3, 0xa8, /* b8-bf */
    202     0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* c0-c7 */
    203     0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* c8-cf */
    204     0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0x9e, /* d0-d7 */
    205     0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0xe1, /* d8-df */
    206     0xb7, 0xb5, 0xb6, 0xc7, 0x8e, 0x8f, 0x92, 0x80, /* e0-e7 */
    207     0xd4, 0x90, 0xd2, 0xd3, 0xde, 0xd6, 0xd7, 0xd8, /* e8-ef */
    208     0xd1, 0xa5, 0xe3, 0xe0, 0xe2, 0xe5, 0x99, 0xf6, /* f0-f7 */
    209     0x9d, 0xeb, 0xe9, 0xea, 0x9a, 0xed, 0xe8, 0x98, /* f8-ff */
    210 #if OLD_TABLE
    211 /* 00 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    212 /* 08 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    213 /* 10 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    214 /* 18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    215 /* 20 */ 0x00, 0x21, 0x00, 0x23, 0x24, 0x25, 0x26, 0x27, /*  !"#$%&' */
    216 /* 28 */ 0x28, 0x29, 0x00, 0x00, 0x00, 0x2D, 0x2E, 0x00, /* ()*+,-./ */
    217 /* 30 */ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 01234567 */
    218 /* 38 */ 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 89:;<=>? */
    219 /* 40 */ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */
    220 /* 48 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* HIJKLMNO */
    221 /* 50 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* PQRSTUVW */
    222 /* 58 */ 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x00, 0x5E, 0x5F, /* XYZ[\]^_ */
    223 /* 60 */ 0x60, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */
    224 /* 68 */ 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, /* hijklmno */
    225 /* 70 */ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* pqrstuvw */
    226 /* 78 */ 0x58, 0x59, 0x5A, 0x5B, 0x7C, 0x00, 0x7E, 0x00, /* xyz{|}~  */
    227 /* 80 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    228 /* 88 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    229 /* 90 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    230 /* 98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    231 /* A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    232 /* A8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    233 /* B0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    234 /* B8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    235 /* C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    236 /* C8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    237 /* D0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    238 /* D8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    239 /* E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    240 /* E8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    241 /* F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    242 /* F8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    243 #endif
     203    0x20, 0x21, 0,    0x23, 0x24, 0x25, 0x26, 0x27, /* 20-27 */
     204    0x28, 0x29, 0,    0,    0,    0x2d,  0,    0,   /* 28-2f */
     205    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, /* 30-37 */
     206    0x38, 0x39, 0,    0,    0,    0,    0,    0,    /* 38-3f */
     207    0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* 40-47 */
     208    0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, /* 48-4f */
     209    0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* 50-57 */
     210    0x58, 0x59, 0x5a, 0,    0,    0,    0x5e, 0x5f, /* 58-5f */
     211    0x60, 0,    0,    0,    0,    0,    0,    0,    /* 60-67 */
     212    0,    0,    0,    0,    0,    0,    0,    0,    /* 68-6f */
     213    0,    0,    0,    0,    0,    0,    0,    0,    /* 70-77 */
     214    0,    0,    0,    0x7b, 0,    0x7d, 0x7e, 0,    /* 78-7f */
     215    0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, /* 80-87 */
     216    0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, /* 88-8f */
     217    0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, /* 90-97 */
     218    0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, /* 98-9f */
     219    0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, /* a0-a7 */
     220    0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, /* a8-af */
     221    0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, /* b0-b7 */
     222    0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, /* b8-bf */
     223    0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, /* c0-c7 */
     224    0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, /* c8-cf */
     225    0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, /* d0-d7 */
     226    0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, /* d8-df */
     227    0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, /* e0-e7 */
     228    0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, /* e8-ef */
     229    0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, /* f0-f7 */
     230    0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff  /* f8-ff */
    244231};
    245 /*
    246  * Convert a unix filename to a DOS filename. Return -1 if wrong name is
    247  * supplied.
    248  */
    249 int
    250 msdos_filename_unix2dos(const char *un, int unlen, char *dn)
    251 {
    252         int i;
    253         uint8_t c;
    254 
    255         /*
    256          * Fill the dos filename string with blanks. These are DOS's pad
    257          * characters.
    258          */
    259         for (i = 0; i <= 10; i++)
    260                 dn[i] = ' ';
    261 
    262         /*
    263          * The filenames "." and ".." are handled specially, since they
    264          * don't follow dos filename rules.
    265          */
    266         if (un[0] == '.' && unlen == 1) {
    267                 dn[0] = '.';
    268                 return 0;
    269         }
    270         if (un[0] == '.' && un[1] == '.' && unlen == 2) {
    271                 dn[0] = '.';
    272                 dn[1] = '.';
    273                 return 0;
    274         }
    275 
     232
     233static uint16_t
     234msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
     235{
     236  uint16_t retval    = 0x0000;
     237  uint16_t char_num  = CF_LE_W( utf16_character );
     238
     239  if ( char_num <= 0x00ff ) {
     240    switch ( char_num )
     241    {
     242      case 0x002b: /* '+' */
     243      case 0x002c: /* ',' */
     244      case 0x002e: /* '.' */
     245      case 0x003b: /* ';' */
     246      case 0x003d: /* '=' */
     247      case 0x005b: /* '[' */
     248      case 0x005d: /* ']' */
     249      case 0x0061: /* 'a' */
     250      case 0x0062: /* 'b' */
     251      case 0x0063: /* 'c' */
     252      case 0x0064: /* 'd' */
     253      case 0x0065: /* 'e' */
     254      case 0x0066: /* 'f' */
     255      case 0x0067: /* 'g' */
     256      case 0x0068: /* 'h' */
     257      case 0x0069: /* 'i' */
     258      case 0x006a: /* 'j' */
     259      case 0x006b: /* 'k' */
     260      case 0x006c: /* 'l' */
     261      case 0x006d: /* 'm' */
     262      case 0x006e: /* 'n' */
     263      case 0x006f: /* 'o' */
     264      case 0x0070: /* 'p' */
     265      case 0x0071: /* 'q' */
     266      case 0x0072: /* 'r' */
     267      case 0x0073: /* 's' */
     268      case 0x0074: /* 't' */
     269      case 0x0075: /* 'u' */
     270      case 0x0076: /* 'v' */
     271      case 0x0077: /* 'w' */
     272      case 0x0078: /* 'x' */
     273      case 0x0079: /* 'y' */
     274      case 0x007a: /* 'z' */
     275        retval = char_num;
     276      break;
     277      default:
     278        retval = codepage_valid_char_map[char_num];
     279      break;
     280    }
     281  }
     282  else
     283    retval = char_num;
     284
     285  return CT_LE_W( retval );
     286}
     287
     288static char
     289msdos_get_valid_codepage_filename_character (const uint8_t character)
     290{
     291  return codepage_valid_char_map[(unsigned int)character];
     292}
     293
     294static ssize_t
     295msdos_filename_process_dot_names (const uint8_t *src_name,
     296                                  const size_t   src_size,
     297                                  uint8_t       *dest_name,
     298                                  const size_t   dest_size)
     299{
     300  ssize_t returned_size = 0;
     301  int     eno           = 0;
    276302  /*
    277    * Remove any dots from the start of a file name.
     303    * The filenames "." and ".." are handled specially, since they
     304    * don't follow dos filename rules.
     305    */
     306   if (    src_name[0] == UTF8_FULL_STOP
     307        && src_size    == UTF8_FULL_STOP_SIZE) {
     308     if (dest_size >= UTF8_FULL_STOP_SIZE) {
     309       dest_name[0]  = UTF8_FULL_STOP;
     310       returned_size = UTF8_FULL_STOP_SIZE;
     311     }
     312     else
     313       eno = ENAMETOOLONG;
     314   }
     315   else if (    eno           == 0
     316             && src_name[0]   == UTF8_FULL_STOP
     317             && src_name[1]   == UTF8_FULL_STOP
     318             && src_size      == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
     319     if (dest_size >= 2 * UTF8_FULL_STOP_SIZE) {
     320       dest_name[0]  = UTF8_FULL_STOP;
     321       dest_name[1]  = UTF8_FULL_STOP;
     322       returned_size = 2 * UTF8_FULL_STOP_SIZE;
     323     }
     324     else
     325       eno = ENAMETOOLONG;
     326   }
     327
     328   if (eno != 0) {
     329     errno         = eno;
     330     returned_size = -1;
     331   }
     332
     333   return returned_size;
     334}
     335
     336static ssize_t
     337msdos_filename_delete_trailing_dots (const uint8_t *filename_utf8,
     338                                     const size_t   filename_size)
     339{
     340  ssize_t      size_returned = filename_size;
     341  unsigned int i;
     342
     343  /*
     344   * Remove any dots from the end of a file name.
    278345   */
    279         while (unlen && (*un == '.')) {
    280                 un++;
    281                 unlen--;
    282         }
    283 
    284         /*
    285          * Copy the unix filename into the dos filename string upto the end
    286          * of string, a '.', or 8 characters. Whichever happens first stops
    287          * us. This forms the name portion of the dos filename. Fold to
    288          * upper case.
    289          */
    290         for (i = 0; i <= 7 && unlen && (c = *un) && c != '.'; i++) {
    291     if (msdos_map[c] == 0)
    292       break;
    293                 dn[i] = msdos_map[c];
    294                 un++;
    295                 unlen--;
    296         }
    297 
    298         /*
    299          * Strip any further characters up to a '.' or the end of the
    300          * string.
    301          */
    302         while (unlen && (c = *un)) {
    303                 un++;
    304                 unlen--;
    305                 /* Make sure we've skipped over the dot before stopping. */
    306                 if (c == '.')
    307                         break;
    308         }
    309 
    310         /*
    311          * Copy in the extension part of the name, if any. Force to upper
    312          * case. Note that the extension is allowed to contain '.'s.
    313          * Filenames in this form are probably inaccessable under dos.
    314          */
    315         for (i = 8; i <= 10 && unlen && (c = *un); i++) {
    316     if (msdos_map[c] == 0)
    317       break;
    318     dn[i] = msdos_map[c];
    319                 un++;
    320                 unlen--;
    321         }
    322         return 0;
    323 }
     346  for ( i = size_returned - UTF8_FULL_STOP_SIZE;
     347           size_returned >= UTF8_FULL_STOP_SIZE
     348        && filename_utf8[i] == UTF8_FULL_STOP;) {
     349    size_returned -= UTF8_FULL_STOP_SIZE;
     350    i             -= UTF8_FULL_STOP_SIZE;
     351  }
     352
     353  return size_returned;
     354}
     355
     356ssize_t
     357msdos_filename_utf8_to_long_name_for_compare (
     358    rtems_dosfs_convert_control     *converter,
     359    const uint8_t                   *utf8_name,
     360    const size_t                     utf8_name_size,
     361    uint8_t                         *long_name,
     362    const size_t                     long_name_size)
     363  {
     364    ssize_t        returned_size = 0;
     365    int            eno           = 0;
     366    size_t         name_size;
     367    size_t         dest_size     = long_name_size;
     368
     369    returned_size = msdos_filename_process_dot_names (
     370      utf8_name,
     371      utf8_name_size,
     372      long_name,
     373      long_name_size);
     374
     375    if (returned_size == 0) {
     376      name_size = msdos_filename_delete_trailing_dots (
     377        &utf8_name[0],
     378        utf8_name_size);
     379      if (name_size > 0) {
     380        eno = (*converter->handler->utf8_normalize_and_fold) (
     381          converter,
     382          utf8_name,
     383          name_size,
     384          long_name,
     385          &dest_size);
     386        if (eno == 0) {
     387          returned_size = (ssize_t)dest_size;
     388        }
     389      } else {
     390        eno = EINVAL;
     391      }
     392    }
     393
     394    if ( eno != 0 ) {
     395      errno         = eno;
     396      returned_size = -1;
     397    }
     398
     399    return returned_size;
     400  }
     401
     402ssize_t
     403msdos_filename_utf8_to_long_name_for_save (
     404    rtems_dosfs_convert_control     *converter,
     405    const uint8_t                   *utf8_name,
     406    const size_t                     utf8_name_size,
     407    uint16_t                        *long_name,
     408    const size_t                     long_name_size)
     409{
     410    ssize_t      returned_size = 0;
     411    int          eno           = 0;
     412    size_t       name_size     = utf8_name_size;
     413    size_t       name_size_tmp = long_name_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
     414    int          i;
     415    uint16_t     c;
     416    unsigned int chars_written;
     417
     418    name_size_tmp = long_name_size;
     419    name_size = msdos_filename_delete_trailing_dots (
     420      &utf8_name[0],
     421      utf8_name_size);
     422    if (name_size > 0) {
     423      /*
     424       * Finally convert from UTF-8 to UTF-16
     425       */
     426      eno = (*converter->handler->utf8_to_utf16) (
     427          converter,
     428          utf8_name,
     429          name_size,
     430          &long_name[0],
     431          &name_size_tmp);
     432      if (eno == 0) {
     433        if (name_size_tmp <= (MSDOS_NAME_MAX_LNF_LEN * MSDOS_NAME_LFN_BYTES_PER_CHAR))
     434          name_size = name_size_tmp;
     435        else
     436          eno = ENAMETOOLONG;
     437      }
     438
     439      if ( eno == 0 )
     440      {
     441        /*
     442         * Validate the characters and assign them to the UTF-16 file name
     443         */
     444        for ( i = 0;
     445                 name_size
     446              && (c = msdos_get_valid_utf16_filename_character ( long_name[i]) );
     447              ++i ) {
     448          long_name[i]   = c;
     449          returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
     450          name_size     -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
     451        }
     452        if ( name_size == UTF16_NULL_SIZE && c == UTF16_NULL ) {
     453          long_name[i]   = c;
     454          returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
     455          name_size     -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
     456        }
     457        else if ( name_size != 0 )
     458          eno = EINVAL;
     459        chars_written = returned_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
     460        if (   long_name [chars_written - 1] != UTF16_NULL
     461            && (returned_size + UTF16_NULL_SIZE ) <= long_name_size ) {
     462          long_name[chars_written] = UTF16_NULL;
     463        }
     464      }
     465    }
     466    else
     467      eno = EINVAL;
     468
     469    if ( eno != 0 ) {
     470      errno         = eno;
     471      returned_size = -1;
     472    }
     473
     474    return returned_size;
     475  }
     476
     477/*
     478 * Remove any dots from the start of a file name.
     479 */
     480static void msdos_filename_remove_prepended_dots (const uint8_t **name_utf8,
     481                                                  size_t         *name_size)
     482{
     483  while (    *name_size >= UTF8_FULL_STOP_SIZE
     484         && **name_utf8 == UTF8_FULL_STOP) {
     485    *name_utf8  += UTF8_FULL_STOP_SIZE;
     486    *name_size  -= UTF8_FULL_STOP_SIZE;
     487  }
     488}
     489
     490ssize_t
     491msdos_filename_utf8_to_short_name_for_compare (
     492    rtems_dosfs_convert_control     *converter,
     493    const uint8_t                   *utf8_name,
     494    const size_t                     utf8_name_size,
     495    void                            *short_name,
     496    const size_t                     short_name_size)
     497{
     498  ssize_t        returned_size           = 0;
     499  int            eno                     = 0;
     500  const uint8_t *name_ptr                = utf8_name;
     501  char          *dest_ptr                = (char*)short_name;
     502  size_t         name_size               = utf8_name_size;
     503  uint8_t        name_normalized_buf[(MSDOS_SHORT_NAME_LEN +1) * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
     504  size_t         name_size_tmp           = sizeof(name_normalized_buf);
     505
     506  returned_size = msdos_filename_process_dot_names (
     507    utf8_name,
     508    utf8_name_size,
     509    short_name,
     510    short_name_size);
     511
     512  if (returned_size == 0) {
     513    msdos_filename_remove_prepended_dots (&name_ptr,
     514                                          &name_size);
     515    if (name_size > 0) {
     516      /*
     517       * Normalize the name and convert to lower case
     518       */
     519      eno = (*converter->handler->utf8_normalize_and_fold) (
     520        converter,
     521        name_ptr,
     522        name_size,
     523        &name_normalized_buf[0],
     524        &name_size_tmp);
     525      name_ptr  = &name_normalized_buf[0];
     526      name_size = name_size_tmp;
     527      if ( eno == ENOMEM ) {
     528        eno = 0;
     529      }
     530      if ( eno == 0 ) {
     531        memcpy (&dest_ptr[0], &name_ptr[0], name_size);
     532        returned_size = name_size;
     533      }
     534    } else
     535      eno = EINVAL;
     536  }
     537
     538  if ( eno != 0 ) {
     539    errno         = eno;
     540    returned_size = -1;
     541  }
     542
     543  return returned_size;
     544}
     545
     546ssize_t
     547msdos_filename_utf8_to_short_name_for_save (
     548    rtems_dosfs_convert_control     *converter,
     549    const uint8_t                   *utf8_name,
     550    const size_t                     utf8_name_size,
     551    void                            *short_name,
     552    const size_t                     short_name_size)
     553{
     554  ssize_t        returned_size           = 0;
     555  int            eno                     = 0;
     556  const uint8_t *name_ptr                = utf8_name;
     557  size_t         name_size               = utf8_name_size;
     558  char          *dest_ptr                = (char*)short_name;
     559  unsigned int   i;
     560  char           c;
     561  size_t         name_size_tmp;
     562  char           name_to_format_buf[MSDOS_SHORT_NAME_LEN +1];
     563
     564  returned_size = msdos_filename_process_dot_names (
     565    utf8_name,
     566    utf8_name_size,
     567    short_name,
     568    short_name_size);
     569
     570  if (returned_size == 0) {
     571    msdos_filename_remove_prepended_dots (&name_ptr,
     572                                          &name_size);
     573
     574    if (name_size > 0) {
     575      /*
     576       * Finally convert from UTF-8 to codepage
     577       */
     578      name_size_tmp = sizeof ( name_to_format_buf );
     579      eno = (*converter->handler->utf8_to_codepage) (
     580        converter,
     581        name_ptr,
     582        name_size,
     583        &name_to_format_buf[0],
     584        &name_size_tmp);
     585      if ( eno != 0 ) {
     586        /* The UTF-8 name my well be long name, for which we now want to
     587         * generate the corresponding short name. Under these circumstances
     588         * eno != 0 likely simply means that the UTF-8 name is longer than 11 characters
     589         * or that it contains unicode characters which can not be converted to the code page
     590         * in a reversible way. Non-reversible characters will be represented by question mark
     591         * characters. Later in this method they will get replaced by underline characters.
     592         */
     593        eno = 0;
     594      }
     595      name_ptr  = (const uint8_t *)(&name_to_format_buf[0]);
     596      name_size = name_size_tmp;
     597      for (i = 0; i < name_size; ++i)
     598        name_to_format_buf[i] = toupper ( (unsigned char)(name_to_format_buf[i]) );
     599      /*
     600       * Validate the characters and assign them to the codepage file name
     601       */
     602      if ( name_size > 0 ) {
     603        /*
     604         * The first character needs some special treatment
     605         */
     606        if ( 0x20 == *name_ptr )
     607          dest_ptr[0] = '_';
     608        else if ( 0xE5 == *name_ptr )
     609          dest_ptr[0] = 0x05;
     610        else if (0 != (c = msdos_get_valid_codepage_filename_character( *name_ptr ) ) )
     611          dest_ptr[0] = c;
     612        else
     613          dest_ptr[0] = '_';
     614        ++name_ptr;
     615        ++returned_size;
     616        --name_size;
     617        /*
     618         * Validate and assign all other characters of the name part
     619         */
     620        for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
     621          c = msdos_get_valid_codepage_filename_character ( *name_ptr );
     622          if (c != 0)
     623            dest_ptr[i] = c;
     624          else
     625            dest_ptr[i] = '_';
     626          ++name_ptr;
     627          ++returned_size;
     628          --name_size;
     629        }
     630        /*
     631         * Strip any further characters up to a '.' or the end of the
     632         * string.
     633         */
     634        if ( *name_ptr == '.' ) {
     635          ++name_ptr;
     636          --name_size;
     637        }
     638
     639        for (; i < 8; ++i) {
     640          dest_ptr[i] = ' ';
     641          ++returned_size;
     642        }
     643
     644        /*
     645         * Copy in the extension part of the name, if any.
     646         */
     647        for (; i <= 10 && name_size ; i++) {
     648          c = msdos_get_valid_codepage_filename_character ( *name_ptr);
     649          if (c != 0)
     650            dest_ptr[i] = c;
     651          else
     652            dest_ptr[i] = '_';
     653          ++name_ptr;
     654          ++returned_size;
     655          name_size--;
     656        }
     657        /*
     658         * Fill up with blanks. These are DOS's pad characters.
     659         */
     660        for ( ; i < short_name_size; ++i ) {
     661          dest_ptr[i] = ' ';
     662          ++returned_size;
     663        }
     664      }
     665    }
     666    else
     667      eno = EINVAL;
     668  }
     669
     670  if ( eno != 0 ) {
     671    errno = eno;
     672    return -1;
     673  }
     674
     675  return returned_size;
     676}
     677
     678
  • cpukit/libfs/src/dosfs/msdos_create.c

    r8bed603 rd2e0bb3  
    9191    }
    9292
    93     name_type = msdos_long_to_short (name, name_len,
     93    name_type = msdos_long_to_short (fs_info->converter,
     94                                     name, name_len,
    9495                                     MSDOS_DIR_NAME(short_node),
    9596                                     MSDOS_NAME_MAX);
  • cpukit/libfs/src/dosfs/msdos_dir.c

    r8bed603 rd2e0bb3  
    99 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
    1010 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
     11 *
     12 *  Modifications to support UTF-8 in the file system are
     13 *  Copyright (c) 2013 embedded brains GmbH.
    1114 *
    1215 *  The license and distribution terms for this file may be
     
    3437#include "msdos.h"
    3538
    36 /*  msdos_format_dirent_with_dot --
    37  *      This routine convert a (short) MSDOS filename as present on disk
    38  *      (fixed 8+3 characters, filled with blanks, without separator dot)
    39  *      to a "normal" format, with between 0 and 8 name chars,
    40  *      a separating dot and up to 3 extension characters
    41  *   Rules to work:
    42  *      - copy any (0-8) "name" part characters that are non-blank
    43  *      - if an extension exists, append a dot
    44  *      - copy any (0-3) non-blank extension characters
    45  *      - append a '\0' (dont count it for the rturn code
    46  *
    47  * PARAMETERS:
    48  *     dst: pointer to destination char array (must be big enough)
    49  *     src: pointer to source characters
    50  *
    51  *
    52  * RETURNS:
    53  *     the number of bytes (without trailing '\0'(written to destination
    54  */
    55 static ssize_t
    56 msdos_format_dirent_with_dot(char *dst,const char *src)
    57 {
    58   ssize_t len;
    59   int i;
    60   const char *src_tmp;
    61 
    62   /*
    63    * find last non-blank character of base name
    64    */
    65   for ((i       =       MSDOS_SHORT_BASE_LEN  ,
    66         src_tmp = src + MSDOS_SHORT_BASE_LEN-1);
    67        ((i > 0) &&
    68         (*src_tmp == ' '));
    69        i--,src_tmp--)
    70     {};
    71   /*
    72    * copy base name to destination
    73    */
    74   src_tmp = src;
    75   len = i;
    76   while (i-- > 0) {
    77     *dst++ = tolower((unsigned char)(*src_tmp++));
    78   }
    79   /*
    80    * find last non-blank character of extension
    81    */
    82   for ((i       =                            MSDOS_SHORT_EXT_LEN  ,
    83         src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1);
    84        ((i > 0) &&
    85         (*src_tmp == ' '));
    86        i--,src_tmp--)
    87     {};
    88   /*
    89    * extension is not empty
    90    */
    91   if (i > 0) {
    92     *dst++ = '.'; /* append dot */
    93     len += i + 1; /* extension + dot */
    94     src_tmp = src + MSDOS_SHORT_BASE_LEN;
    95     while (i-- > 0) {
    96       *dst++ = tolower((unsigned char)(*src_tmp++));
    97       len++;
    98     }
    99   }
    100   *dst = '\0'; /* terminate string */
    101 
    102   return len;
    103 }
     39
    10440
    10541/*  msdos_dir_read --
     
    12965{
    13066    int                rc = RC_OK;
     67    int                eno = 0;
    13168    rtems_status_code  sc = RTEMS_SUCCESSFUL;
    13269    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
     70    rtems_dosfs_convert_control *converter = fs_info->converter;
     71    const rtems_dosfs_convert_handler *convert_handler = converter->handler;
    13372    fat_file_fd_t     *fat_fd = iop->pathinfo.node_access;
    13473    fat_file_fd_t     *tmp_fat_fd = NULL;
    13574    struct dirent      tmp_dirent;
     75    size_t             tmp_lfn_len = 0;
     76    uint16_t          *lfn_buf = converter->buffer.data;
     77    char              *sfn_buf = converter->buffer.data;
     78    const size_t       buf_size = converter->buffer.size;
    13679    uint32_t           start = 0;
    13780    ssize_t            ret = 0;
     
    14386    uint8_t            lfn_checksum = 0;
    14487    int                lfn_entries = 0;
     88    size_t             string_size = sizeof(tmp_dirent.d_name);
     89    bool               is_first_entry;
    14590
    14691    /*
     
    168113        rtems_set_errno_and_return_minus_one(EIO);
    169114
    170     while (count > 0)
     115    while (count > 0 && cmpltd >= 0)
    171116    {
    172117        /*
     
    184129        }
    185130
    186         for (i = 0; i < ret; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
     131        for (i = 0; i < ret && cmpltd >= 0; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
    187132        {
    188133            char* entry = (char*) fs_info->cl_buf + i;
     
    214159                MSDOS_ATTR_LFN)
    215160            {
    216                 int   o;
    217                 char* p;
    218                 int   q;
     161                int offset_lfn;
    219162
    220163                /*
     
    223166                if (lfn_start == FAT_FILE_SHORT_NAME)
    224167                {
     168                    is_first_entry = true;
    225169                    /*
    226170                     * The first entry must have the last long entry flag set.
     
    242186                    lfn_entries = (*MSDOS_DIR_ENTRY_TYPE(entry) &
    243187                                   MSDOS_LAST_LONG_ENTRY_MASK);
     188                    tmp_lfn_len = 0;
    244189                    lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
    245190                    memset (tmp_dirent.d_name, 0, sizeof(tmp_dirent.d_name));
    246191                }
     192                else
     193                    is_first_entry = false;
    247194
    248195                /*
     
    263210                 * Extract the file name into the directory entry. The data is
    264211                 * stored in UNICODE characters (16bit). No translation is
    265                  * currently supported.
     212                 * done for the possibly partial entry.
     213                 * Once all entries have been assembled to a UTF-16 file name,
     214                 * this file name will get converted to UTF-8.
    266215                 *
    267216                 * The DOS maximum length is 255 characters without the
     
    271220
    272221                lfn_entries--;
    273                 p = entry + 1;
    274                 o = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY;
    275 
    276                 for (q = 0; q < MSDOS_LFN_LEN_PER_ENTRY; q++)
    277                 {
    278                     if (o >= (sizeof(tmp_dirent.d_name) - 1))
    279                         break;
    280 
    281                     tmp_dirent.d_name[o++] = *p;
    282 
    283                     if (*p == '\0')
    284                         break;
    285 
    286                     switch (q)
    287                     {
    288                         case 4:
    289                             p += 5;
    290                             break;
    291                         case 10:
    292                             p += 4;
    293                             break;
    294                         default:
    295                             p += 2;
    296                             break;
    297                     }
    298                 }
     222                offset_lfn = lfn_entries * MSDOS_LFN_LEN_PER_ENTRY;
     223                tmp_lfn_len += msdos_get_utf16_string_from_long_entry (
     224                  entry,
     225                  &lfn_buf[offset_lfn],
     226                  buf_size - offset_lfn,
     227                  is_first_entry
     228                );
    299229            }
    300230            else
     
    345275
    346276                /*
    347                  * If a long file name check if the correct number of
    348                  * entries have been found and if the checksum is correct.
    349                  * If not return the short file name.
     277                 * If a long file name check if the correct number of entries
     278                 * have been found and if the checksum is correct and if it is
     279                 * convertable to utf8 string.  If not return the short file
     280                 * name.
    350281                 */
    351282                if (lfn_start != FAT_FILE_SHORT_NAME)
     
    360291                    if (lfn_entries || (lfn_checksum != cs))
    361292                        lfn_start = FAT_FILE_SHORT_NAME;
     293
     294                    eno = (*convert_handler->utf16_to_utf8) (
     295                        converter,
     296                        lfn_buf,
     297                        tmp_lfn_len,
     298                        (uint8_t*)(&tmp_dirent.d_name[0]),
     299                        &string_size);
     300                    if (eno == 0) {
     301                      tmp_dirent.d_namlen                    = string_size;
     302                      tmp_dirent.d_name[tmp_dirent.d_namlen] = '\0';
     303                    }
     304                    else {
     305                        lfn_start = FAT_FILE_SHORT_NAME;
     306                    }
    362307                }
    363308
     
    369314                     */
    370315                    tmp_dirent.d_namlen = msdos_format_dirent_with_dot(
    371                         tmp_dirent.d_name, entry); /* src text */
    372                 }
    373                 else
    374                 {
    375                     tmp_dirent.d_namlen = strlen(tmp_dirent.d_name);
    376                 }
    377 
    378                 memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
    379 
    380                 iop->offset = iop->offset + sizeof(struct dirent);
    381                 cmpltd += (sizeof(struct dirent));
    382                 count -= (sizeof(struct dirent));
    383 
    384                 /* inode number extracted, close fat-file */
    385                 rc = fat_file_close(&fs_info->fat, tmp_fat_fd);
    386                 if (rc != RC_OK)
    387                 {
    388                     rtems_semaphore_release(fs_info->vol_sema);
    389                     return rc;
     316                        sfn_buf, entry); /* src text */
     317                    eno = (*convert_handler->codepage_to_utf8) (
     318                        converter,
     319                        sfn_buf,
     320                        tmp_dirent.d_namlen,
     321                        (uint8_t*)(&tmp_dirent.d_name[0]),
     322                        &string_size);
     323                    if ( 0 == eno ) {
     324                      tmp_dirent.d_namlen                    = string_size;
     325                      tmp_dirent.d_name[tmp_dirent.d_namlen] = '\0';
     326                    }
     327                    else {
     328                        cmpltd = -1;
     329                        errno  = eno;
     330                    }
     331                }
     332
     333                if ( cmpltd >= 0 ) {
     334                    memcpy(buffer + cmpltd, &tmp_dirent, sizeof(struct dirent));
     335
     336                    iop->offset = iop->offset + sizeof(struct dirent);
     337                    cmpltd += (sizeof(struct dirent));
     338                    count -= (sizeof(struct dirent));
     339
     340                    /* inode number extracted, close fat-file */
     341                    rc = fat_file_close(&fs_info->fat, tmp_fat_fd);
     342                    if (rc != RC_OK)
     343                    {
     344                        rtems_semaphore_release(fs_info->vol_sema);
     345                        return rc;
     346                    }
    390347                }
    391348            }
  • cpukit/libfs/src/dosfs/msdos_fsunmount.c

    r8bed603 rd2e0bb3  
    4848    msdos_fs_info_t *fs_info = temp_mt_entry->fs_info;
    4949    fat_file_fd_t   *fat_fd = temp_mt_entry->mt_fs_root->location.node_access;
     50    rtems_dosfs_convert_control *converter = fs_info->converter;
    5051
    51     /* close fat-file which correspondes to root directory */
     52    /* close fat-file which corresponds to root directory */
    5253    fat_file_close(&fs_info->fat, fat_fd);
    5354
     
    5556
    5657    rtems_semaphore_delete(fs_info->vol_sema);
     58    (*converter->handler->destroy)( converter );
    5759    free(fs_info->cl_buf);
    5860    free(temp_mt_entry->fs_info);
  • cpukit/libfs/src/dosfs/msdos_init.c

    r8bed603 rd2e0bb3  
    1212 *  Modifications to support reference counting in the file system are
    1313 *  Copyright (c) 2012 embedded brains GmbH.
     14 *
     15 *  Modifications to support UTF-8 in the file system are
     16 *  Copyright (c) 2013 embedded brains GmbH.
    1417 *
    1518 *  The license and distribution terms for this file may be
     
    9093 *
    9194 */
    92 int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
    93                            const void                           *data)
     95int rtems_dosfs_initialize(
     96  rtems_filesystem_mount_table_entry_t *mt_entry,
     97  const void                           *data
     98)
    9499{
    95     int rc;
     100    int                                rc = 0;
     101    const rtems_dosfs_mount_options   *mount_options = data;
     102    rtems_dosfs_convert_control       *converter;
    96103
    97     rc = msdos_initialize_support(mt_entry,
    98                                   &msdos_ops,
    99                                   &msdos_file_handlers,
    100                                   &msdos_dir_handlers);
     104
     105    if (mount_options == NULL || mount_options->converter == NULL) {
     106        converter = rtems_dosfs_create_default_converter();
     107    } else {
     108        converter = mount_options->converter;
     109    }
     110
     111    if (converter != NULL) {
     112        rc = msdos_initialize_support(mt_entry,
     113                                      &msdos_ops,
     114                                      &msdos_file_handlers,
     115                                      &msdos_dir_handlers,
     116                                      converter);
     117    } else {
     118        errno = ENOMEM;
     119        rc = -1;
     120    }
     121
    101122    return rc;
    102123}
  • cpukit/libfs/src/dosfs/msdos_initsupp.c

    r8bed603 rd2e0bb3  
    5353    const rtems_filesystem_operations_table *op_table,
    5454    const rtems_filesystem_file_handlers_r  *file_handlers,
    55     const rtems_filesystem_file_handlers_r  *directory_handlers
     55    const rtems_filesystem_file_handlers_r  *directory_handlers,
     56    rtems_dosfs_convert_control             *converter
    5657    )
    5758{
     
    6869
    6970    temp_mt_entry->fs_info = fs_info;
     71
     72    fs_info->converter = converter;
    7073
    7174    rc = fat_init_volume_info(&fs_info->fat, temp_mt_entry->dev);
  • cpukit/libfs/src/dosfs/msdos_misc.c

    r8bed603 rd2e0bb3  
    99 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
    1010 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
     11 *
     12 *  Modifications to support UTF-8 in the file system are
     13 *  Copyright (c) 2013 embedded brains GmbH.
    1114 *
    1215 *  The license and distribution terms for this file may be
     
    2730#include <string.h>
    2831#include <assert.h>
     32#include <errno.h>
     33#include <inttypes.h>
    2934#include <rtems/libio_.h>
    3035
     
    7075
    7176    if ((ch == '.') || isalnum((unsigned char)ch) ||
    72         (strchr("$%'-_@~`!(){}^#&", ch) != NULL))
     77        (strchr("$%'-_@~`!(){}^#&", ch) != NULL) || (unsigned char) ch > 127)
    7378        return MSDOS_NAME_SHORT;
    7479
     
    193198#define MSDOS_L2S_PRINT 0
    194199msdos_name_type_t
    195 msdos_long_to_short(const char *lfn, int lfn_len, char* sfn, int sfn_len)
     200msdos_long_to_short(rtems_dosfs_convert_control     *converter,
     201                    const char                      *lfn,
     202                    int                              lfn_len,
     203                    char                            *sfn,
     204                    int                              sfn_len)
    196205{
    197206    msdos_name_type_t type;
     207    int               eno = 0;
    198208    int               i;
     209    ssize_t           short_filename_length = sfn_len;
     210    void             *buffer = converter->buffer.data;
     211    size_t            codepage_name_len = converter->buffer.size;
    199212
    200213    /*
     
    243256     */
    244257
    245     type = msdos_name_type (lfn, lfn_len);
    246 
    247     if (type == MSDOS_NAME_INVALID)
     258    eno = (*converter->handler->utf8_to_codepage) (
     259        converter,
     260        (const uint8_t*)&lfn[0],
     261        lfn_len,
     262        buffer,
     263        &codepage_name_len);
     264    if (eno == EINVAL)
     265    {
     266        eno = 0;
     267        type = MSDOS_NAME_LONG;
     268    }
     269    else
     270    {
     271        type = msdos_name_type (
     272            buffer,
     273            codepage_name_len);
     274    }
     275
     276    if (type != MSDOS_NAME_INVALID)
     277    {
     278        short_filename_length = msdos_filename_utf8_to_short_name_for_save (
     279            converter,
     280            (const uint8_t*)lfn,
     281            lfn_len,
     282            sfn,
     283            short_filename_length);
     284        if (short_filename_length < 0 ) {
     285            type = MSDOS_NAME_INVALID;
     286        }
     287#if MSDOS_L2S_PRINT
     288        printf ("MSDOS_L2S: TYPE:%d lfn:'%s' SFN:'%s'\n", type, lfn, sfn);
     289#endif
     290    }
     291    else
    248292    {
    249293#if MSDOS_L2S_PRINT
    250294        printf ("MSDOS_L2S: INVALID[2]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
    251295#endif
    252         return MSDOS_NAME_INVALID;
    253     }
    254 
    255     msdos_filename_unix2dos (lfn, lfn_len, sfn);
    256 
    257 #if MSDOS_L2S_PRINT
    258     printf ("MSDOS_L2S: TYPE:%d lfn:'%s' SFN:'%s'\n", type, lfn, sfn);
    259 #endif
     296    }
     297
    260298    return type;
    261299}
     
    293331    memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    294332
    295     name_type = msdos_long_to_short (name,
    296                                      name_len,
    297                                      MSDOS_DIR_NAME(node_entry),
    298                                      MSDOS_NAME_MAX);
     333    name_type = msdos_long_to_short (
     334        fs_info->converter,
     335        name,
     336        name_len,
     337        MSDOS_DIR_NAME(node_entry),
     338        MSDOS_NAME_MAX);
    299339
    300340    /*
    301      * find the node which correspondes to the name in the directory pointed by
     341     * find the node which corresponds to the name in the directory pointed by
    302342     * 'parent_loc'
    303343     */
     
    427467    /* find name in fat-file which corresponds to the directory */
    428468    rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd,
    429                                      create_node, name, name_len, name_type,
     469                                     create_node, (const uint8_t*)name, name_len, name_type,
    430470                                     dir_pos, name_dir_entry);
    431471    if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
     
    519559    char             dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
    520560    uint32_t         cl4find = 0;
     561    rtems_dosfs_convert_control *converter = fs_info->converter;
    521562
    522563    /*
     
    543584    /* find "." node in opened directory */
    544585    memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    545     msdos_long_to_short(".", 1, dot_node, MSDOS_SHORT_NAME_LEN);
    546     rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, ".", 1,
     586    msdos_long_to_short(
     587        converter,
     588        ".", 1, dot_node, MSDOS_SHORT_NAME_LEN);
     589    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)".", 1,
    547590                                     MSDOS_NAME_SHORT, dir_pos, dot_node);
    548591
     
    555598    /* find ".." node in opened directory */
    556599    memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    557     msdos_long_to_short("..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN);
    558     rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, "..", 2,
     600    msdos_long_to_short(
     601        converter,
     602        "..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN);
     603    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)"..", 2,
    559604                                     MSDOS_NAME_SHORT, dir_pos,
    560605                                     dotdot_node);
     
    915960}
    916961
    917 /* msdos_create_name_in_fat_file --
    918  *     This routine creates an entry in the fat file for the file name
    919  *     provided by the user. The directory entry passed is the short
    920  *     file name and is added as it. If the file name is long a long
    921  *     file name set of entries is added.
    922  *
    923  *     Scan the directory for the file and if not found add the new entry.
    924  *     When scanning remember the offset in the file where the directory
    925  *     entry can be added.
     962#define MSDOS_FIND_PRINT 0
     963static int
     964msdos_on_entry_found (
     965    msdos_fs_info_t                      *fs_info,
     966    fat_file_fd_t                        *fat_fd,
     967    const uint32_t                        bts2rd,
     968    char                                 *name_dir_entry,
     969    char                                 *entry,
     970    fat_dir_pos_t                        *dir_pos,
     971    uint32_t                             *dir_offset,
     972    const uint32_t                        dir_entry,
     973    const fat_pos_t                      *lfn_start
     974)
     975{
     976    int rc = RC_OK;
     977#if MSDOS_FIND_PRINT
     978    printf ("MSFS:[9.3] SNF found\n");
     979#endif
     980    /*
     981     * We get the entry we looked for - fill the position
     982     * structure and the 32 bytes of the short entry
     983     */
     984    rc = fat_file_ioctl(&fs_info->fat,
     985                        fat_fd,
     986                        F_CLU_NUM,
     987                        *dir_offset * bts2rd,
     988                        &dir_pos->sname.cln);
     989    if (rc == RC_OK) {
     990        dir_pos->sname.ofs = dir_entry;
     991
     992        if (lfn_start->cln != FAT_FILE_SHORT_NAME)
     993        {
     994            rc = fat_file_ioctl (&fs_info->fat,
     995                                 fat_fd,
     996                                 F_CLU_NUM,
     997                                 lfn_start->cln * bts2rd,
     998                                 &lfn_start->cln);
     999        }
     1000        if ( rc == RC_OK ) {
     1001            dir_pos->lname.cln = lfn_start->cln;
     1002            dir_pos->lname.ofs = lfn_start->ofs;
     1003
     1004            memcpy(name_dir_entry, entry,
     1005                   MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
     1006        }
     1007    }
     1008
     1009    return rc;
     1010}
     1011
     1012ssize_t
     1013msdos_get_utf16_string_from_long_entry (
     1014    const char                 *entry,
     1015    uint16_t                   *entry_string_buf,
     1016    const size_t                buf_size,
     1017    bool                        is_first_entry
     1018)
     1019{
     1020    ssize_t chars_in_entry;
     1021
     1022    if (buf_size >= MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR) {
     1023        memcpy (&entry_string_buf[0],  &entry[1],  10 );
     1024        memcpy (&entry_string_buf[5],  &entry[14], 12 );
     1025        memcpy (&entry_string_buf[11], &entry[28],  4 );
     1026
     1027        if (is_first_entry) {
     1028            for (chars_in_entry = 0;
     1029                 (    entry_string_buf[chars_in_entry] != 0x0000
     1030                  && chars_in_entry < MSDOS_LFN_LEN_PER_ENTRY );
     1031                  ++chars_in_entry) {
     1032                ;
     1033            }
     1034        }
     1035        else
     1036            chars_in_entry = MSDOS_LFN_LEN_PER_ENTRY;
     1037
     1038        return chars_in_entry * MSDOS_NAME_LFN_BYTES_PER_CHAR;
     1039    }
     1040    else
     1041        return ENOMEM;
     1042}
     1043
     1044/*  msdos_format_dirent_with_dot --
     1045 *      This routine convert a (short) MSDOS filename as present on disk
     1046 *      (fixed 8+3 characters, filled with blanks, without separator dot)
     1047 *      to a "normal" format, with between 0 and 8 name chars,
     1048 *      a separating dot and up to 3 extension characters
     1049 *   Rules to work:
     1050 *      - copy any (0-8) "name" part characters that are non-blank
     1051 *      - if an extension exists, append a dot
     1052 *      - copy any (0-3) non-blank extension characters
     1053 *      - append a '\0' (dont count it for the rturn code
    9261054 *
    9271055 * PARAMETERS:
    928  *     mt_entry       - mount table entry
    929  *     fat_fd         - fat-file descriptor
    930  *     name           - NULL or name to find
    931  *     paux           - identify a node location on the disk -
    932  *                      number of cluster and offset inside the cluster
    933  *     name_dir_entry - node to create/placeholder for found node
     1056 *     dst: pointer to destination char array (must be big enough)
     1057 *     src: pointer to source characters
     1058 *
    9341059 *
    9351060 * RETURNS:
    936  *     RC_OK on success, or error code if error occured (errno set
    937  *     appropriately)
    938  *
     1061 *     the number of bytes (without trailing '\0'(written to destination
    9391062 */
    940 #define MSDOS_FIND_PRINT 0
    941 int msdos_find_name_in_fat_file(
    942     rtems_filesystem_mount_table_entry_t *mt_entry,
     1063ssize_t
     1064msdos_format_dirent_with_dot(char *dst,const char *src)
     1065{
     1066  ssize_t len;
     1067  int i;
     1068  const char *src_tmp;
     1069
     1070  /*
     1071   * find last non-blank character of base name
     1072   */
     1073  for (i = MSDOS_SHORT_BASE_LEN, src_tmp = src + MSDOS_SHORT_BASE_LEN - 1;
     1074       i > 0 && *src_tmp == ' ';
     1075       --i,--src_tmp)
     1076    {};
     1077  /*
     1078   * copy base name to destination
     1079   */
     1080  src_tmp = src;
     1081  len = i;
     1082  while (i-- > 0) {
     1083    *dst++ = tolower((unsigned char)(*src_tmp++));
     1084  }
     1085  /*
     1086   * find last non-blank character of extension
     1087   */
     1088  for (i = MSDOS_SHORT_EXT_LEN,
     1089        src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1;
     1090       i > 0 && *src_tmp == ' ';
     1091       --i, --src_tmp)
     1092    {};
     1093  /*
     1094   * extension is not empty
     1095   */
     1096  if (i > 0) {
     1097    *dst++ = '.'; /* append dot */
     1098    ++len;        /* dot */
     1099    src_tmp = src + MSDOS_SHORT_BASE_LEN;
     1100    while (i-- > 0) {
     1101      *dst++ = tolower((unsigned char)(*src_tmp++));
     1102      ++len;
     1103    }
     1104  }
     1105  *dst = '\0'; /* terminate string */
     1106
     1107  return len;
     1108}
     1109
     1110static ssize_t
     1111msdos_long_entry_to_utf8_name (
     1112    rtems_dosfs_convert_control *converter,
     1113    const char                  *entry,
     1114    const bool                   is_first_entry,
     1115    uint8_t                     *entry_utf8_buf,
     1116    const size_t                 buf_size)
     1117{
     1118    ssize_t      retval         = 0;
     1119    int          eno            = 0;
     1120    size_t       bytes_in_utf8  = buf_size;
     1121    size_t       bytes_in_buf;
     1122    uint16_t     entry_string[MSDOS_LFN_LEN_PER_ENTRY];
     1123
     1124    retval = msdos_get_utf16_string_from_long_entry (
     1125        entry,
     1126        entry_string,
     1127        sizeof (entry_string),
     1128        is_first_entry
     1129    );
     1130
     1131    if (retval >= 0) {
     1132        bytes_in_buf = retval;
     1133        eno = (*converter->handler->utf16_to_utf8) (
     1134            converter,
     1135            &entry_string[0],
     1136            bytes_in_buf,
     1137            &entry_utf8_buf[0],
     1138            &bytes_in_utf8);
     1139        if ( eno == 0 ) {
     1140            retval = bytes_in_utf8;
     1141        }
     1142    }
     1143
     1144    if (eno != 0) {
     1145        retval = -1;
     1146        errno  = eno;
     1147    }
     1148
     1149    return retval;
     1150}
     1151
     1152static ssize_t msdos_short_entry_to_utf8_name (
     1153  rtems_dosfs_convert_control     *converter,
     1154  const char                      *entry,
     1155  uint8_t                         *buf,
     1156  const size_t                     buf_size)
     1157{
     1158  char         char_buf[MSDOS_NAME_MAX_WITH_DOT];
     1159  int          eno             = 0;
     1160  size_t       bytes_converted = buf_size;
     1161  ssize_t      bytes_written   = msdos_format_dirent_with_dot(char_buf, entry);
     1162
     1163  if (bytes_written > 0) {
     1164    if (char_buf[0] == 0x05)
     1165      char_buf[0] = 0xE5;
     1166
     1167    eno = (*converter->handler->codepage_to_utf8) (
     1168        converter,
     1169        char_buf,
     1170        bytes_written,
     1171        buf,
     1172        &bytes_converted);
     1173    if (eno == 0)
     1174        bytes_written = bytes_converted;
     1175  } else {
     1176      eno = EINVAL;
     1177  }
     1178
     1179  if (eno != 0) {
     1180      bytes_written = -1;
     1181      errno         = eno;
     1182  }
     1183
     1184  return bytes_written;
     1185}
     1186
     1187static ssize_t
     1188msdos_compare_entry_against_filename (
     1189    rtems_dosfs_convert_control *converter,
     1190    const uint8_t               *entry,
     1191    const size_t                 entry_size,
     1192    const uint8_t               *filename,
     1193    const size_t                 filename_size_remaining,
     1194    bool                        *is_matching)
     1195{
     1196  ssize_t      size_remaining = filename_size_remaining;
     1197  int          eno            = 0;
     1198  uint8_t      entry_normalized[( MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_LFN_BYTES_PER_CHAR * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
     1199  size_t       bytes_in_entry_normalized = sizeof ( entry_normalized );
     1200
     1201  eno = (*converter->handler->utf8_normalize_and_fold) (
     1202      converter,
     1203      &entry[0],
     1204      entry_size,
     1205      &entry_normalized[0],
     1206      &bytes_in_entry_normalized);
     1207  if (eno == 0) {
     1208#if MSDOS_FIND_PRINT > 1
     1209        printf ( "MSFS:[6] entry_normalized:%s"
     1210                 "name:%s\n",
     1211                 entry,
     1212                 filename );
     1213#endif
     1214        if (bytes_in_entry_normalized <= size_remaining) {
     1215            size_remaining = size_remaining - bytes_in_entry_normalized;
     1216            if (0 == memcmp ( &entry_normalized[0],
     1217                              &filename[size_remaining],
     1218                              bytes_in_entry_normalized)) {
     1219                *is_matching = true;
     1220            } else {
     1221                *is_matching   = false;
     1222                size_remaining = filename_size_remaining;
     1223            }
     1224
     1225        }
     1226        else {
     1227          *is_matching = false;
     1228        }
     1229    }
     1230
     1231    if (eno != 0) {
     1232      size_remaining = -1;
     1233      errno          = eno;
     1234    }
     1235
     1236    return size_remaining;
     1237}
     1238
     1239static int
     1240msdos_find_file_in_directory (
     1241    const uint8_t                        *filename_converted,
     1242    const size_t                          name_len_for_compare,
     1243    const size_t                          name_len_for_save,
     1244    const msdos_name_type_t               name_type,
     1245    msdos_fs_info_t                      *fs_info,
    9431246    fat_file_fd_t                        *fat_fd,
    944     bool                                  create_node,
    945     const char                           *name,
    946     int                                   name_len,
    947     msdos_name_type_t                     name_type,
     1247    const uint32_t                        bts2rd,
     1248    const bool                            create_node,
     1249    const unsigned int                    fat_entries,
     1250    char                                 *name_dir_entry,
    9481251    fat_dir_pos_t                        *dir_pos,
    949     char                                 *name_dir_entry
    950                                 )
    951 {
    952     ssize_t          ret = 0;
    953     msdos_fs_info_t *fs_info = mt_entry->fs_info;
    954     uint32_t         dir_offset = 0;
    955     uint32_t         dir_entry = 0;
    956     uint32_t         bts2rd = 0;
    957     fat_pos_t        lfn_start;
    958     bool             lfn_matched = false;
    959     uint8_t          lfn_checksum = 0;
    960     int              lfn_entries;
    961     int              lfn_entry = 0;
    962     uint32_t         empty_space_offset = 0;
    963     uint32_t         empty_space_entry = 0;
    964     uint32_t         empty_space_count = 0;
    965     bool             empty_space_found = false;
    966     uint32_t         entries_per_block;
    967     bool             read_cluster = false;
    968 
    969     assert(name_len > 0);
    970 
    971     fat_dir_pos_init(dir_pos);
    972 
    973     lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
    974 
    975     /*
    976      * Set the number of short entries needed to store the LFN. If the name
    977      * is short still check for possible long entries with the short name.
    978      *
    979      * In PR1491 we need to have a LFN for a short file name entry. To
    980      * test this make this test always fail, ie add "0 &&".
    981      */
    982     if (create_node && (name_type == MSDOS_NAME_SHORT))
    983       lfn_entries = 0;
    984     else
    985       lfn_entries =
    986         ((name_len - 1) + MSDOS_LFN_LEN_PER_ENTRY) / MSDOS_LFN_LEN_PER_ENTRY;
    987 
    988     if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
    989         (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
    990         bts2rd = fat_fd->fat_file_size;
    991     else
    992         bts2rd = fs_info->fat.vol.bpc;
    993 
    994     entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
    995 
    996 #if MSDOS_FIND_PRINT
    997     printf ("MSFS:[1] nt:%d, cn:%i ebp:%li bts2rd:%li lfne:%d nl:%i n:%s\n",
    998             name_type, create_node, entries_per_block, bts2rd,
    999             lfn_entries, name_len, name);
    1000 #endif
     1252    uint32_t                             *dir_offset,
     1253    uint32_t                             *empty_space_offset,
     1254    uint32_t                             *empty_space_entry,
     1255    uint32_t                             *empty_space_count)
     1256{
     1257    int               rc                = RC_OK;
     1258    ssize_t           bytes_read;
     1259    uint32_t          dir_entry;
     1260    fat_pos_t         lfn_start;
     1261    uint8_t           lfn_checksum      = 0;
     1262    bool              entry_matched       = false;
     1263    bool              empty_space_found = false;
     1264    uint32_t          entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
     1265    int               lfn_entry         = 0;
     1266    uint8_t           entry_utf8_normalized[(MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_LFN_BYTES_PER_CHAR * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR/*MSDOS_ENTRY_LFN_UTF8_BYTES*/];
     1267    size_t            bytes_in_entry;
     1268    bool              filename_matched  = false;
     1269    ssize_t           filename_size_remaining = name_len_for_compare;
     1270    rtems_dosfs_convert_control *converter = fs_info->converter;
     1271
    10011272    /*
    10021273     * Scan the directory seeing if the file is present. While
     
    10041275     * create the entry if the name is not found.
    10051276     */
    1006     while ((ret = fat_file_read(&fs_info->fat, fat_fd, (dir_offset * bts2rd),
    1007                                 bts2rd, fs_info->cl_buf)) != FAT_EOF)
     1277
     1278    lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
     1279
     1280    while (   (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (*dir_offset * bts2rd),
     1281                                             bts2rd, fs_info->cl_buf)) != FAT_EOF
     1282           && rc == RC_OK)
    10081283    {
    10091284        bool remainder_empty = false;
    10101285#if MSDOS_FIND_PRINT
    1011         printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
    1012 #endif
    1013 
    1014         if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
     1286        printf ("MSFS:[2] dir_offset:%li\n", *dir_offset);
     1287#endif
     1288
     1289        if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
    10151290            rtems_set_errno_and_return_minus_one(EIO);
    10161291
    1017         assert(ret == bts2rd);
     1292        assert(bytes_read == bts2rd);
    10181293
    10191294        /* have to look at the DIR_NAME as "raw" 8-bit data */
    10201295        for (dir_entry = 0;
    1021              dir_entry < bts2rd;
     1296             dir_entry < bts2rd && rc == RC_OK && (! filename_matched);
    10221297             dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
    10231298        {
     
    10261301            /*
    10271302             * See if the entry is empty or the remainder of the directory is
    1028              * empty ? Localise to make the code read better.
     1303             * empty ? Localize to make the code read better.
    10291304             */
    10301305            bool entry_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
     
    10341309#if MSDOS_FIND_PRINT
    10351310            printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
    1036                     remainder_empty, entry_empty, dir_offset,
     1311                    remainder_empty, entry_empty, *dir_offset,
    10371312                    dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
    10381313#endif
     
    10441319             * is a count of empty entries.
    10451320             */
    1046             if (empty_space_count == 0)
     1321            if (*empty_space_count == 0)
    10471322            {
    1048                 empty_space_entry = dir_entry;
    1049                 empty_space_offset = dir_offset;
     1323                *empty_space_entry = dir_entry;
     1324                *empty_space_offset = *dir_offset;
    10501325            }
    10511326
     
    10601335                 */
    10611336                if (!create_node)
    1062                     return MSDOS_NAME_NOT_FOUND_ERR;
     1337                    rc = MSDOS_NAME_NOT_FOUND_ERR;
    10631338
    10641339                /*
     
    10681343                 * are needed FAT_EOF is returned by the read and we extend the file.
    10691344                 */
    1070                 if (!empty_space_found)
     1345                if (   !empty_space_found
     1346                    && rc == RC_OK )
    10711347                {
    1072                   empty_space_count +=
     1348                    *empty_space_count +=
    10731349                    entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    1074                   empty_space_found = true;
    1075 #if MSDOS_FIND_PRINT
    1076                   printf ("MSFS:[3.2] esf:%i esc%i\n", empty_space_found, empty_space_count);
     1350                    empty_space_found = true;
     1351#if MSDOS_FIND_PRINT
     1352                    printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_space_count );
    10771353#endif
    10781354                }
     
    10831359                if (create_node)
    10841360                {
    1085                   /*
    1086                    * Remainder is not empty so is this entry empty ?
    1087                    */
    1088                   empty_space_count++;
    1089 
    1090                   if (empty_space_count == (lfn_entries + 1))
    1091                     empty_space_found = true;
     1361                    /*
     1362                     * Remainder is not empty so is this entry empty ?
     1363                     */
     1364                    (*empty_space_count)++;
     1365
     1366                    if (*empty_space_count == (fat_entries + 1))
     1367                        empty_space_found = true;
    10921368                }
    10931369#if MSDOS_FIND_PRINT
    10941370                printf ("MSFS:[4.1] esc:%li esf:%i\n",
    1095                         empty_space_count, empty_space_found);
     1371                        *empty_space_count, empty_space_found);
    10961372#endif
    10971373            }
     
    11061382                if (create_node && !empty_space_found)
    11071383                {
    1108                     empty_space_entry = 0;
    1109                     empty_space_count = 0;
     1384                    *empty_space_entry = 0;
     1385                    *empty_space_count = 0;
    11101386                }
    11111387
     
    11171393                    MSDOS_ATTR_LFN)
    11181394                {
    1119                     char* p;
    1120                     int   o;
    1121                     int   i;
     1395/*                    int   o;*/
    11221396#if MSDOS_FIND_PRINT
    11231397                    printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
     
    11321406                    if (lfn_start.cln == FAT_FILE_SHORT_NAME)
    11331407                    {
    1134                         lfn_matched = false;
     1408                        entry_matched = false;
    11351409
    11361410                        /*
     
    11491423                         * on when the characters are checked.
    11501424                         */
    1151                         if (lfn_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) &
     1425                        if (fat_entries != (*MSDOS_DIR_ENTRY_TYPE(entry) &
    11521426                                            MSDOS_LAST_LONG_ENTRY_MASK))
    11531427                            continue;
     
    11561430                         * Get the checksum of the short entry.
    11571431                         */
    1158                         lfn_start.cln = dir_offset;
     1432                        lfn_start.cln = *dir_offset;
    11591433                        lfn_start.ofs = dir_entry;
    1160                         lfn_entry = lfn_entries;
     1434                        lfn_entry = fat_entries;
    11611435                        lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
    11621436
    11631437#if MSDOS_FIND_PRINT
    11641438                        printf ("MSFS:[4.3] lfn_checksum:%i\n",
    1165                                 *MSDOS_DIR_LFN_CHECKSUM(entry));
     1439                                lfn_checksum);
    11661440#endif
    11671441                    }
     
    11831457                        continue;
    11841458                    }
    1185 
     1459#if MSDOS_FIND_PRINT
     1460                    printf ("MSFS:[5] lfne:%i\n", lfn_entry);
     1461#endif
    11861462                    lfn_entry--;
    1187                     o = lfn_entry * MSDOS_LFN_LEN_PER_ENTRY;
    1188                     p = entry + 1;
    1189 
    1190 #if MSDOS_FIND_PRINT
    1191                     printf ("MSFS:[5] lfne:%i\n", lfn_entry);
    1192 #endif
    1193                     for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++)
    1194                     {
    1195 #if MSDOS_FIND_PRINT > 1
    1196                         printf ("MSFS:[6] o:%i i:%i *p:%c(%02x) name[o + i]:%c(%02x)\n",
    1197                                 o, i, *p, *p, name[o + i], name[o + i]);
    1198 #endif
    1199                         if (*p == '\0')
    1200                         {
    1201                             /*
    1202                              * If this is the first entry, ie the last part of the
    1203                              * long file name and the length does not match then
    1204                              * the file names do not match.
    1205                              */
    1206                             if (((lfn_entry + 1) == lfn_entries) &&
    1207                                 ((o + i) != name_len))
    1208                                 lfn_start.cln = FAT_FILE_SHORT_NAME;
    1209                             break;
     1463
     1464                    bytes_in_entry = msdos_long_entry_to_utf8_name (
     1465                        converter,
     1466                        entry,
     1467                        (lfn_entry + 1) == fat_entries,
     1468                        &entry_utf8_normalized[0],
     1469                        sizeof (entry_utf8_normalized));
     1470                    if (bytes_in_entry > 0) {
     1471                        filename_size_remaining = msdos_compare_entry_against_filename (
     1472                            converter,
     1473                            &entry_utf8_normalized[0],
     1474                            bytes_in_entry,
     1475                            &filename_converted[0],
     1476                            filename_size_remaining,
     1477                            &entry_matched);
     1478
     1479                        if (filename_size_remaining < 0
     1480                            || (! entry_matched)) {
     1481                            filename_size_remaining = name_len_for_compare;
     1482                            lfn_start.cln = FAT_FILE_SHORT_NAME;
    12101483                        }
    1211 
    1212                         if (((o + i) >= name_len) || (*p != name[o + i]))
    1213                         {
    1214                             lfn_start.cln = FAT_FILE_SHORT_NAME;
    1215                             break;
    1216                         }
    1217 
    1218                         switch (i)
    1219                         {
    1220                             case 4:
    1221                                 p += 5;
    1222                                 break;
    1223                             case 10:
    1224                                 p += 4;
    1225                                 break;
    1226                             default:
    1227                                 p += 2;
    1228                                 break;
    1229                         }
     1484                    } else {
     1485                      lfn_start.cln = FAT_FILE_SHORT_NAME;
     1486                      entry_matched   = false;
    12301487                    }
    1231 
    1232                     lfn_matched = ((lfn_entry == 0) &&
    1233                                    (lfn_start.cln != FAT_FILE_SHORT_NAME));
    1234 
    1235 #if MSDOS_FIND_PRINT
    1236                     printf ("MSFS:[8.1] lfn_matched:%i\n", lfn_matched);
    1237 #endif
    12381488                }
    12391489                else
    12401490                {
    12411491#if MSDOS_FIND_PRINT
    1242                     printf ("MSFS:[9.1] SFN entry, lfn_matched:%i\n", lfn_matched);
     1492                    printf ("MSFS:[9.1] SFN entry, entry_matched:%i\n", entry_matched);
    12431493#endif
    12441494                    /*
     
    12501500                     * name entry.
    12511501                     */
    1252                     if (lfn_matched)
     1502                    if (entry_matched)
    12531503                    {
    12541504                        uint8_t  cs = 0;
     
    12601510
    12611511                        if (lfn_entry || (lfn_checksum != cs))
    1262                             lfn_matched = false;
    1263 #if MSDOS_FIND_PRINT
    1264                         printf ("MSFS:[9.2] checksum, lfn_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
    1265                                 lfn_matched, lfn_entry, lfn_checksum, cs);
    1266 #endif
     1512                            entry_matched = false;
     1513                        else {
     1514                            filename_matched = true;
     1515                            rc = msdos_on_entry_found (
     1516                                fs_info,
     1517                                fat_fd,
     1518                                bts2rd,
     1519                                name_dir_entry,
     1520                                entry,
     1521                                dir_pos,
     1522                                dir_offset,
     1523                                dir_entry,
     1524                                &lfn_start
     1525                            );
     1526                        }
     1527
     1528#if MSDOS_FIND_PRINT
     1529                        printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
     1530                                entry_matched, lfn_entry, lfn_checksum, cs);
     1531#endif
     1532                    } else {
     1533                        bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
     1534                        bytes_in_entry = msdos_short_entry_to_utf8_name (
     1535                            converter,
     1536                            MSDOS_DIR_NAME (entry),
     1537                            &entry_utf8_normalized[0],
     1538                            bytes_in_entry);
     1539                        if (bytes_in_entry > 0) {
     1540                            filename_size_remaining = msdos_compare_entry_against_filename (
     1541                                converter,
     1542                                &entry_utf8_normalized[0],
     1543                                bytes_in_entry,
     1544                                &filename_converted[0],
     1545                                name_len_for_compare,
     1546                                &entry_matched);
     1547                            if (entry_matched && filename_size_remaining == 0) {
     1548                                filename_matched = true;
     1549                                rc = msdos_on_entry_found (
     1550                                    fs_info,
     1551                                    fat_fd,
     1552                                    bts2rd,
     1553                                    name_dir_entry,
     1554                                    entry,
     1555                                    dir_pos,
     1556                                    dir_offset,
     1557                                    dir_entry,
     1558                                    &lfn_start
     1559                                );
     1560                            }
     1561                            if (rc == RC_OK && (! filename_matched)) {
     1562                                lfn_start.cln           = FAT_FILE_SHORT_NAME;
     1563                                entry_matched           = false;
     1564                                filename_size_remaining = name_len_for_compare;
     1565                            }
     1566                        } else {
     1567                          lfn_start.cln           = FAT_FILE_SHORT_NAME;
     1568                          entry_matched           = false;
     1569                          filename_size_remaining = name_len_for_compare;
     1570                        }
    12671571                    }
    1268 
    1269                     /*
    1270                      * If the long file names matched or the file name is
    1271                      * short and they match then we have the entry. We will not
    1272                      * match a long file name against a short file name because
    1273                      * a long file name that generates a matching short file
    1274                      * name is not a long file name.
    1275                      */
    1276                     if (lfn_matched ||
    1277                         ((name_type == MSDOS_NAME_SHORT) &&
    1278                          (lfn_start.cln == FAT_FILE_SHORT_NAME) &&
    1279                          (memcmp(MSDOS_DIR_NAME(entry),
    1280                                  MSDOS_DIR_NAME(name_dir_entry),
    1281                                  MSDOS_SHORT_NAME_LEN) == 0)))
    1282                     {
    1283 #if MSDOS_FIND_PRINT
    1284                         printf ("MSFS:[9.3] SNF found\n");
    1285 #endif
    1286                         /*
    1287                          * We get the entry we looked for - fill the position
    1288                          * structure and the 32 bytes of the short entry
    1289                          */
    1290                         int rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
    1291                                                 dir_offset * bts2rd,
    1292                                                 &dir_pos->sname.cln);
    1293                         if (rc != RC_OK)
    1294                             return rc;
    1295 
    1296                         dir_pos->sname.ofs = dir_entry;
    1297 
    1298                         if (lfn_start.cln != FAT_FILE_SHORT_NAME)
    1299                         {
    1300                           rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
    1301                                               lfn_start.cln * bts2rd,
    1302                                               &lfn_start.cln);
    1303                           if (rc != RC_OK)
    1304                             return rc;
    1305                         }
    1306 
    1307                         dir_pos->lname.cln = lfn_start.cln;
    1308                         dir_pos->lname.ofs = lfn_start.ofs;
    1309 
    1310                         memcpy(name_dir_entry, entry,
    1311                                MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    1312                         return RC_OK;
    1313                     }
    1314 
    1315                     lfn_start.cln = FAT_FILE_SHORT_NAME;
    1316                     lfn_matched = false;
    13171572                }
    13181573            }
    13191574        }
    13201575
    1321         if (remainder_empty)
     1576        if (filename_matched || remainder_empty)
    13221577            break;
    13231578
    1324         dir_offset++;
    1325     }
    1326 
    1327     /*
    1328      * If we are not to create the entry return a not found error.
    1329      */
    1330     if (!create_node)
    1331       return MSDOS_NAME_NOT_FOUND_ERR;
    1332 
    1333 #if MSDOS_FIND_PRINT
    1334     printf ("MSFS:[8.1] WRITE do:%ld esc:%ld eso:%ld ese:%ld\n",
    1335             dir_offset, empty_space_count, empty_space_offset, empty_space_entry);
    1336 #endif
     1579        (*dir_offset)++;
     1580    }
     1581    if ( ! filename_matched ) {
     1582        /*
     1583         * If we are not to create the entry return a not found error.
     1584         */
     1585        if (!create_node)
     1586            rc = MSDOS_NAME_NOT_FOUND_ERR;
     1587
     1588#if MSDOS_FIND_PRINT
     1589        printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" eso:%"PRIu32" ese:%"PRIu32"\n",
     1590                 *dir_offset, *empty_space_count, *empty_space_offset, *empty_space_entry );
     1591#endif
     1592    }
     1593
     1594    return rc;
     1595}
     1596
     1597static int
     1598msdos_add_file (
     1599    const char                           *name_converted,
     1600    const msdos_name_type_t               name_type,
     1601    msdos_fs_info_t                      *fs_info,
     1602    fat_file_fd_t                        *fat_fd,
     1603    const uint32_t                        bts2rd,
     1604    const unsigned int                    fat_entries,
     1605    const char                           *name_dir_entry,
     1606    fat_dir_pos_t                        *dir_pos,
     1607    const uint32_t                        dir_offset,
     1608    const uint32_t                        empty_space_offset_param,
     1609    const uint32_t                        empty_space_entry_param,
     1610    const uint32_t                        empty_space_count
     1611
     1612)
     1613{
     1614    int              ret                = 0;
     1615    ssize_t          bytes_written      = 0;
     1616    uint8_t          lfn_checksum       = 0;
     1617    uint32_t         empty_space_offset = empty_space_offset_param;
     1618    uint32_t         empty_space_entry  = empty_space_entry_param;
     1619    bool             read_cluster       = false;
     1620    int              lfn_entry          = 0;
     1621    fat_pos_t        lfn_start;
     1622    uint32_t         dir_entry;
    13371623
    13381624    /*
     
    13421628     * in this directory.
    13431629     */
    1344     lfn_checksum = 0;
    13451630    if (name_type == MSDOS_NAME_LONG)
    13461631    {
    13471632        int      slot = (((empty_space_offset * bts2rd) + empty_space_entry) /
    1348                          MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1;
     1633                        MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + fat_entries + 1;
    13491634        msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
    13501635    }
    13511636
    1352     if (lfn_entries)
     1637    if (fat_entries)
    13531638    {
    13541639        uint8_t* p = (uint8_t*) MSDOS_DIR_NAME(name_dir_entry);
     
    13931678     * The one more is the short entry.
    13941679     */
    1395     while (lfn_entry < (lfn_entries + 1))
     1680    while (lfn_entry < (fat_entries + 1))
    13961681    {
    13971682        int length = 0;
     
    13991684        if (read_cluster)
    14001685        {
    1401           uint32_t new_length;
    1402 #if MSDOS_FIND_PRINT
    1403           printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
    1404 #endif
    1405           ret = fat_file_read(&fs_info->fat, fat_fd,
    1406                               (empty_space_offset * bts2rd), bts2rd,
    1407                               fs_info->cl_buf);
    1408 
    1409           if (ret != bts2rd)
    1410           {
    1411             if (ret != FAT_EOF)
    1412               rtems_set_errno_and_return_minus_one(EIO);
    1413 
    1414 #if MSDOS_FIND_PRINT
    1415             printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
    1416 #endif
    1417             ret = fat_file_extend (&fs_info->fat, fat_fd, false,
    1418                                    empty_space_offset * bts2rd, &new_length);
    1419 
    1420             if (ret != RC_OK)
    1421               return ret;
    1422 
    1423 #if MSDOS_FIND_PRINT
    1424             printf ("MSFS:[9.3] extended: %d <-> %d\n", new_length, empty_space_offset * bts2rd);
    1425 #endif
    1426             if (new_length != (empty_space_offset * bts2rd))
    1427               rtems_set_errno_and_return_minus_one(EIO);
    1428 
    1429             memset(fs_info->cl_buf, 0, bts2rd);
    1430 
    1431             ret = fat_file_write(&fs_info->fat, fat_fd,
    1432                                  empty_space_offset * bts2rd,
    1433                                  bts2rd, fs_info->cl_buf);
    1434 #if MSDOS_FIND_PRINT
    1435             printf ("MSFS:[9.4] clear write: %d\n", ret);
    1436 #endif
    1437             if (ret == -1)
    1438               return ret;
    1439             else if (ret != bts2rd)
    1440               rtems_set_errno_and_return_minus_one(EIO);
    1441           }
     1686            uint32_t new_length;
     1687#if MSDOS_FIND_PRINT
     1688            printf ("MSFS:[9.1] eso:%li\n", empty_space_offset);
     1689#endif
     1690            ret = fat_file_read(&fs_info->fat, fat_fd,
     1691                                (empty_space_offset * bts2rd), bts2rd,
     1692                                fs_info->cl_buf);
     1693
     1694            if (ret != bts2rd)
     1695            {
     1696                if (ret != FAT_EOF)
     1697                    rtems_set_errno_and_return_minus_one(EIO);
     1698
     1699#if MSDOS_FIND_PRINT
     1700                printf ("MSFS:[9.2] extending file:%li\n", empty_space_offset);
     1701#endif
     1702                ret = fat_file_extend (&fs_info->fat, fat_fd, false,
     1703                                       empty_space_offset * bts2rd, &new_length);
     1704
     1705                if (ret != RC_OK)
     1706                    return ret;
     1707
     1708#if MSDOS_FIND_PRINT
     1709                printf ("MSFS:[9.3] extended: %"PRIu32" <-> %"PRIu32"\n", new_length, empty_space_offset * bts2rd);
     1710#endif
     1711                if (new_length != (empty_space_offset * bts2rd))
     1712                    rtems_set_errno_and_return_minus_one(EIO);
     1713
     1714                memset(fs_info->cl_buf, 0, bts2rd);
     1715
     1716                bytes_written = fat_file_write(&fs_info->fat, fat_fd,
     1717                                               empty_space_offset * bts2rd,
     1718                                               bts2rd, fs_info->cl_buf);
     1719#if MSDOS_FIND_PRINT
     1720                printf ("MSFS:[9.4] clear write: %d\n", ret);
     1721#endif
     1722                if (bytes_written == -1)
     1723                    return -1;
     1724                else if (bytes_written != bts2rd)
     1725                    rtems_set_errno_and_return_minus_one(EIO);
     1726            }
    14421727        }
    14431728
     
    14671752             * Time to write the short file name entry.
    14681753             */
    1469             if (lfn_entry == (lfn_entries + 1))
     1754            if (lfn_entry == (fat_entries + 1))
    14701755            {
    14711756                /* get current cluster number */
    1472                 int rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
    1473                                         empty_space_offset * bts2rd,
    1474                                         &dir_pos->sname.cln);
    1475                 if (rc != RC_OK)
    1476                   return rc;
     1757                ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
     1758                                    empty_space_offset * bts2rd,
     1759                                    &dir_pos->sname.cln);
     1760                if (ret != RC_OK)
     1761                    return ret;
    14771762
    14781763                dir_pos->sname.ofs = dir_entry;
     
    14801765                if (lfn_start.cln != FAT_FILE_SHORT_NAME)
    14811766                {
    1482                   rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
    1483                                       lfn_start.cln * bts2rd,
    1484                                       &lfn_start.cln);
    1485                   if (rc != RC_OK)
    1486                     return rc;
     1767                    ret = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
     1768                                        lfn_start.cln * bts2rd,
     1769                                        &lfn_start.cln);
     1770                    if (ret != RC_OK)
     1771                        return ret;
    14871772                }
    14881773
     
    15041789            if (lfn_start.cln == FAT_FILE_SHORT_NAME)
    15051790            {
    1506               lfn_start.cln = empty_space_offset;
    1507               lfn_start.ofs = dir_entry;
     1791                lfn_start.cln = empty_space_offset;
     1792                lfn_start.ofs = dir_entry;
    15081793            }
    15091794
     
    15161801
    15171802            p = entry + 1;
    1518             n = name + (lfn_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY;
    1519 
    1520             for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; i++)
     1803            n = name_converted + (fat_entries - lfn_entry) * MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR;
     1804
     1805#if MSDOS_FIND_PRINT
     1806            printf ("MSFS:[11] ");
     1807#endif
     1808            for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
    15211809            {
    1522                 if (*n != 0)
     1810                if (!(*n == 0 && *(n+1) == 0))
    15231811                {
    15241812                    *p = *n;
    1525                     n++;
     1813                    *(p+1) = *(n+1);
    15261814                }
    15271815                else
     
    15311819                    fill = 0xff;
    15321820                }
     1821                n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
     1822#if MSDOS_FIND_PRINT
     1823                printf ( "'%c''%c'", *p, *(p+1) );
     1824#endif
    15331825
    15341826                switch (i)
     
    15451837                }
    15461838            }
    1547 
    1548             *MSDOS_DIR_ENTRY_TYPE(entry) = (lfn_entries - lfn_entry) + 1;
     1839#if MSDOS_FIND_PRINT
     1840            printf ( "\n" );
     1841#endif
     1842            *MSDOS_DIR_ENTRY_TYPE(entry) = (fat_entries - lfn_entry) + 1;
    15491843            if (lfn_entry == 1)
    15501844                *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
     
    15521846        }
    15531847
    1554         ret = fat_file_write(&fs_info->fat, fat_fd,
    1555                              (empty_space_offset * bts2rd) + empty_space_entry,
    1556                              length, fs_info->cl_buf + empty_space_entry);
    1557         if (ret == -1)
    1558             return ret;
    1559         else if (ret != length)
     1848        bytes_written = fat_file_write(&fs_info->fat, fat_fd,
     1849                                       (empty_space_offset * bts2rd) + empty_space_entry,
     1850                                       length, fs_info->cl_buf + empty_space_entry);
     1851        if (bytes_written == -1)
     1852            return -1;
     1853        else if (bytes_written != length)
    15601854            rtems_set_errno_and_return_minus_one(EIO);
    15611855
     
    15641858        read_cluster = true;
    15651859    }
    1566 
    1567     return 0;
    1568 }
     1860    return ret;
     1861}
     1862
     1863int
     1864msdos_find_name_in_fat_file (
     1865    rtems_filesystem_mount_table_entry_t *mt_entry,
     1866    fat_file_fd_t                        *fat_fd,
     1867    bool                                  create_node,
     1868    const uint8_t                        *name_utf8,
     1869    int                                   name_utf8_len,
     1870    msdos_name_type_t                     name_type,
     1871    fat_dir_pos_t                        *dir_pos,
     1872    char                                 *name_dir_entry)
     1873{
     1874    int                                retval                     = 0;
     1875    msdos_fs_info_t                   *fs_info                    = mt_entry->fs_info;
     1876    ssize_t                            name_len_for_save;
     1877    ssize_t                            name_len_for_compare;
     1878    uint32_t                           bts2rd                     = 0;
     1879    uint32_t                           empty_space_offset         = 0;
     1880    uint32_t                           empty_space_entry          = 0;
     1881    uint32_t                           empty_space_count          = 0;
     1882    uint32_t                           dir_offset                 = 0;
     1883    unsigned int                       fat_entries;
     1884    rtems_dosfs_convert_control       *converter = fs_info->converter;
     1885    void                              *buffer = converter->buffer.data;
     1886    size_t                             buffer_size = converter->buffer.size;
     1887
     1888    assert(name_utf8_len > 0);
     1889
     1890    fat_dir_pos_init(dir_pos);
     1891
     1892
     1893
     1894    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
     1895        (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
     1896        bts2rd = fat_fd->fat_file_size;
     1897    else
     1898        bts2rd = fs_info->fat.vol.bpc;
     1899
     1900    switch ( name_type ) {
     1901        case MSDOS_NAME_SHORT:
     1902            name_len_for_compare = msdos_filename_utf8_to_short_name_for_compare (
     1903                converter,
     1904                name_utf8,
     1905                name_utf8_len,
     1906                buffer,
     1907                MSDOS_SHORT_NAME_LEN);
     1908            if (name_len_for_compare > 0) {
     1909                fat_entries = 0;
     1910            }
     1911            else
     1912                retval = -1;
     1913        break;
     1914        case MSDOS_NAME_LONG:
     1915            name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
     1916                converter,
     1917                name_utf8,
     1918                name_utf8_len,
     1919                buffer,
     1920                buffer_size);
     1921            if (name_len_for_save > 0) {
     1922                fat_entries = (name_len_for_save -1
     1923                               + (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR)) / (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR);
     1924                name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
     1925                  converter,
     1926                  name_utf8,
     1927                  name_utf8_len,
     1928                  buffer,
     1929                  buffer_size);
     1930                if (0 >= name_len_for_compare) {
     1931                    retval = -1;
     1932                }
     1933            }
     1934            else
     1935                retval = -1;
     1936        break;
     1937        case MSDOS_NAME_INVALID:
     1938        default:
     1939            errno = EINVAL;
     1940            retval = -1;
     1941        break;
     1942    }
     1943    if (retval == RC_OK) {
     1944      /* See if the file/directory does already exist */
     1945      retval = msdos_find_file_in_directory (
     1946          buffer,
     1947          name_len_for_compare,
     1948          name_len_for_save,
     1949          name_type,
     1950          fs_info,
     1951          fat_fd,
     1952          bts2rd,
     1953          create_node,
     1954          fat_entries,
     1955          name_dir_entry,
     1956          dir_pos,
     1957          &dir_offset,
     1958          &empty_space_offset,
     1959          &empty_space_entry,
     1960          &empty_space_count);
     1961    }
     1962    /* Create a non-existing file/directory if requested */
     1963    if (   retval == RC_OK
     1964        && create_node) {
     1965        switch (name_type) {
     1966          case MSDOS_NAME_SHORT:
     1967              name_len_for_save = msdos_filename_utf8_to_short_name_for_save (
     1968                  converter,
     1969                  name_utf8,
     1970                  name_utf8_len,
     1971                  buffer,
     1972                  MSDOS_SHORT_NAME_LEN);
     1973              if (name_len_for_save > 0 ) {
     1974                  fat_entries = 0;
     1975              }
     1976              else
     1977                  retval = -1;
     1978          break;
     1979          case MSDOS_NAME_LONG:
     1980              name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
     1981                  converter,
     1982                  name_utf8,
     1983                  name_utf8_len,
     1984                  buffer,
     1985                  buffer_size);
     1986              if (name_len_for_save > 0) {
     1987                fat_entries = (name_len_for_save -1
     1988                               + (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR)) / (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR);
     1989
     1990              }
     1991              else
     1992                  retval = -1;
     1993          break;
     1994          case MSDOS_NAME_INVALID:
     1995          default:
     1996              errno = EINVAL;
     1997              retval = -1;
     1998          break;
     1999        }
     2000        retval = msdos_add_file (
     2001            buffer,
     2002            name_type,
     2003            fs_info,
     2004            fat_fd,
     2005            bts2rd,
     2006            fat_entries,
     2007            name_dir_entry,
     2008            dir_pos,
     2009            dir_offset,
     2010            empty_space_offset,
     2011            empty_space_entry,
     2012            empty_space_count
     2013        );
     2014    }
     2015
     2016    return retval;
     2017}
     2018
    15692019
    15702020/* msdos_find_node_by_cluster_num_in_fat_file --
Note: See TracChangeset for help on using the changeset viewer.