Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:13

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @brief Application Interface to FAT Filesystem
0007  *
0008  * @ingroup DOSFS
0009  */
0010 
0011 /*
0012  *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
0013  *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
0014  *
0015  *  Modifications to support UTF-8 in the file system are
0016  *  Copyright (c) 2013 embedded brains GmbH & Co. KG
0017  *
0018  * Redistribution and use in source and binary forms, with or without
0019  * modification, are permitted provided that the following conditions
0020  * are met:
0021  * 1. Redistributions of source code must retain the above copyright
0022  *    notice, this list of conditions and the following disclaimer.
0023  * 2. Redistributions in binary form must reproduce the above copyright
0024  *    notice, this list of conditions and the following disclaimer in the
0025  *    documentation and/or other materials provided with the distribution.
0026  *
0027  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0028  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0029  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0030  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0031  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0032  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0033  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0034  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0035  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0036  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0037  * POSSIBILITY OF SUCH DAMAGE.
0038  */
0039 
0040 #ifndef _RTEMS_DOSFS_H
0041 #define _RTEMS_DOSFS_H
0042 
0043 #include <rtems.h>
0044 #include <rtems/libio.h>
0045 
0046 #ifdef __cplusplus
0047 extern "C" {
0048 #endif
0049 
0050 typedef struct rtems_dosfs_convert_control rtems_dosfs_convert_control;
0051 
0052 /**
0053  * @brief Converts from UTF-8 into a specific code page.
0054  *
0055  * @param[in,out] self The convert control.
0056  * @param[in] src A well-formed UTF-8 string to be converted.
0057  * @param[in] src_size The size of the string in bytes (inludes '\\0' if any).
0058  * @param[out] dst The address the converted string will get copied to.
0059  * @param[in,out] dst_size The size of the buffer in bytes respectively the
0060  * number of bytes written to the buffer.
0061  *
0062  * @retval 0 Successful operation.
0063  * @retval EINVAL Conversion was successful, but is not reversible.
0064  * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
0065  */
0066 typedef int (*rtems_dosfs_utf8_to_codepage)(
0067   rtems_dosfs_convert_control *self,
0068   const uint8_t               *src,
0069   size_t                       src_size,
0070   char                        *dst,
0071   size_t                      *dst_size
0072 );
0073 
0074 /**
0075  * @brief Converts from a specific code page into UTF-8
0076  *
0077  * @param[in,out] self The convert control.
0078  * @param[in] src A well-formed string in code page format.
0079  * @param[in] src_size The size of the string in bytes (inludes '\\0' if any).
0080  * @param[out] dst The address the converted string will get copied to.
0081  * @param[in,out] dst_size The size of the buffer in bytes respectively the
0082  * number of bytes written to the buffer.
0083  *
0084  * @retval 0 Successful operation.
0085  * @retval EINVAL Conversion was successful, but is not reversible.
0086  * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
0087  */
0088 typedef int (*rtems_dosfs_codepage_to_utf8)(
0089   rtems_dosfs_convert_control *self,
0090   const char                  *src,
0091   size_t                       src_size,
0092   uint8_t                     *dst,
0093   size_t                      *dst_size
0094 );
0095 
0096 /**
0097  * @brief Converts from UTF-8 to UTF-16
0098  *
0099  * @param[in,out] self The convert control.
0100  * @param[in] src A well-formed UTF-8 string to be converted.
0101  * @param[in] src_size The size of the string in bytes (inludes '\\0' if any).
0102  * @param[out] dst The address the converted string will get copied to
0103  * @param[in,out] dst_size The size of the buffer in bytes respectively the
0104  * number of bytes written to the buffer.
0105  *
0106  * @retval 0 Successful operation.
0107  * @retval EINVAL Conversion was successful, but is not reversible.
0108  * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
0109  */
0110 typedef int (*rtems_dosfs_utf8_to_utf16)(
0111   rtems_dosfs_convert_control *self,
0112   const uint8_t               *src,
0113   size_t                       src_size,
0114   uint16_t                    *dst,
0115   size_t                      *dst_size
0116 );
0117 
0118 /**
0119  * @brief Converts from UTF-16 to UTF-8.
0120  *
0121  * @param[in,out] self The convert control.
0122  * @param[in] src A well-formed UTF-16 string to be converted.
0123  * @param[in] src_size The size of the string in bytes (inludes '\\0' if any).
0124  * @param[out] dst The address the converted string will get copied to.
0125  * @param[in,out] dst_size The size of the buffer in bytes respectively the
0126  * number of bytes written to the buffer
0127  *
0128  * @retval 0 Successful operation.
0129  * @retval EINVAL Conversion was successful, but is not reversible.
0130  * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
0131  */
0132 typedef int (*rtems_dosfs_utf16_to_utf8)(
0133   rtems_dosfs_convert_control *self,
0134   const uint16_t              *src,
0135   size_t                       src_size,
0136   uint8_t                     *dst,
0137   size_t                      *dst_size
0138 );
0139 
0140 /**
0141  * @brief Converts from UTF-8 to Normalized Form Canonical Decomposition.
0142  *
0143  * Does canonical decomposition of the UTF-8 string and in addition
0144  * also converts upper case alphabetic characters to lower case characters
0145  *
0146  * @param[in,out] self The convert control.
0147  * @param[in] src A well-formed UTF-8 string to be normalized and fold.
0148  * @param[in] src_size The size of the string in bytes (inludes '\\0' if any).
0149  * @param[out] dst The address the normalized and fold string will get
0150  * copied to.
0151  * @param[in,out] dst_size The size of the buffer in bytes respectively the
0152  * number of bytes written to the buffer.
0153  *
0154  * @retval 0 Successful operation.
0155  * @retval EINVAL Conversion failed.
0156  * @retval ENOMEM Conversion failed (possibly due to insufficient buffer size).
0157  * @retval EOVERFLOW Conversion failed.
0158  * @retval ENOENT Conversion failed.
0159  */
0160 typedef int (*rtems_dosfs_utf8_normalize_and_fold)(
0161   rtems_dosfs_convert_control *self,
0162   const uint8_t               *src,
0163   size_t                       src_size,
0164   uint8_t                     *dst,
0165   size_t                      *dst_size
0166 );
0167 
0168 /**
0169  * @brief Destroys a convert control structure.
0170  *
0171  * @param[in,out] self The convert control for destruction.
0172  */
0173 typedef void (*rtems_dosfs_convert_destroy)(
0174   rtems_dosfs_convert_control *self
0175 );
0176 
0177 /**
0178  * @brief FAT filesystem convert handler.
0179  */
0180 typedef struct {
0181   rtems_dosfs_utf8_to_codepage        utf8_to_codepage;
0182   rtems_dosfs_codepage_to_utf8        codepage_to_utf8;
0183   rtems_dosfs_utf8_to_utf16           utf8_to_utf16;
0184   rtems_dosfs_utf16_to_utf8           utf16_to_utf8;
0185   rtems_dosfs_utf8_normalize_and_fold utf8_normalize_and_fold;
0186   rtems_dosfs_convert_destroy         destroy;
0187 } rtems_dosfs_convert_handler;
0188 
0189 typedef struct {
0190   void   *data;
0191   size_t  size;
0192 } rtems_dosfs_buffer;
0193 
0194 /**
0195  * @brief FAT filesystem convert control.
0196  *
0197  * Short file names are stored in the code page format.  Long file names are
0198  * stored as little-endian UTF-16.  The convert control determines the format
0199  * conversions to and from the POSIX file name strings.
0200  */
0201 struct rtems_dosfs_convert_control {
0202   const rtems_dosfs_convert_handler *handler;
0203   rtems_dosfs_buffer                 buffer;
0204 };
0205 
0206 /**
0207  * @defgroup DOSFS FAT Filesystem Support
0208  *
0209  * @ingroup FileSystemTypesAndMount
0210  *
0211  * @brief FAT file system configuration support, format and mount options.
0212  *
0213  * A block device can be formatted with a FAT file system with the
0214  * msdos_format() function.
0215  *
0216  * The FAT file system mount operation can be controlled with FAT file system
0217  * specific mount options, see @ref rtems_dosfs_mount_options.
0218  *
0219  * @{
0220  */
0221 
0222 /**
0223  * @brief Semaphore count per FAT filesystem instance.
0224  *
0225  * This can be used for system configuration via <rtems/confdefs.h>.
0226  */
0227 #define RTEMS_DOSFS_SEMAPHORES_PER_INSTANCE 1
0228 
0229 /**
0230  * @brief FAT filesystem mount options.
0231  */
0232 typedef struct {
0233   /**
0234    * @brief Converter implementation for new file system instance.
0235    *
0236    * Note: If you pass a converter to mount, you have to destroy it yourself if
0237    * mount failed. In a good case it is destroyed at unmount.
0238    *
0239    * Before converters have been added to the RTEMS implementation of the FAT
0240    * file system, the implementation was:
0241    * - Short names were saved in code page format (as is still the case).
0242    * - Long names were not saved in UTF-16 format as mandated by the FAT file
0243    *   system specification.  Instead the character in the local encoding was
0244    *   stored to the low byte directly and the high byte was set to zero.
0245    *
0246    * There are a few compatibility issues due to a non-standard conform
0247    * implementation of the FAT file system before the UTF-8 support was added.
0248    * These following issues affect the default converter and the UTF-8
0249    * converter:
0250    * - Before UTF-8 support was added, it was possible to create files with the
0251    *   the same short name in single case and mixed case in a directory.  It
0252    *   was for example possible to have files "ABC" and "aBc" in a single
0253    *   directory.  Now this bug is fixed.
0254    * - Before UTF-8 support was added, it was possible to create files with a
0255    *   name length of slightly more than 255 characters.  Now the
0256    *   implementation adheres exactly to the 255 character limit.
0257    * - Long file names saved before UTF-8 support was added could contain
0258    *   non-ASCII characters in the low byte which was saved for a long name
0259    *   character.  With the default converter this means such files can be read
0260    *   only by their short file name.  With the UTF-8 converter file names will
0261    *   be read correctly as long as the characters written with the old
0262    *   implementation were Latin-1 characters.
0263    *
0264    * The following sample code demonstrates how to mount a file
0265    * system with UTF-8 support:
0266    * @code
0267    * #include <errno.h>
0268    * #include <assert.h>
0269    * #include <rtems/dosfs.h>
0270    * #include <rtems/libio.h>
0271    *
0272    * static int mount_with_utf8(
0273    *   const char *device_file,
0274    *   const char *mount_point
0275    * )
0276    * {
0277    *   rtems_dosfs_convert_control *convert_ctrl;
0278    *   int                          rv;
0279    *
0280    *   convert_ctrl = rtems_dosfs_create_utf8_converter( "CP850" );
0281    *
0282    *   if ( convert_ctrl != NULL ) {
0283    *     rtems_dosfs_mount_options mount_opts;
0284    *
0285    *     memset( &mount_opts, 0, sizeof( mount_opts ) );
0286    *     mount_opts.converter = convert_ctrl;
0287    *
0288    *     rv = mount_and_make_target_path(
0289    *       device_file,
0290    *       mount_point,
0291    *       RTEMS_FILESYSTEM_TYPE_DOSFS,
0292    *       RTEMS_FILESYSTEM_READ_WRITE,
0293    *       &mount_opts
0294    *     );
0295    *
0296    *     if (rv != 0) {
0297    *       (*mount_opts.converter->handler->destroy)(mount_opts.converter);
0298    *     }
0299    *   } else {
0300    *     rv = -1;
0301    *     errno = ENOMEM;
0302    *   }
0303    *
0304    *   return rv;
0305    * }
0306    * @endcode
0307    *
0308    * In case you do not want UTF-8 support, you can simply pass a NULL pointer
0309    * to mount_and_make_target_path() respectively to mount() instead of the
0310    * mount_opts address.
0311    *
0312    * @see rtems_dosfs_create_default_converter() and
0313    * rtems_dosfs_create_utf8_converter().
0314    */
0315   rtems_dosfs_convert_control *converter;
0316 } rtems_dosfs_mount_options;
0317 
0318 /**
0319  * @brief Allocates and initializes a default converter.
0320  *
0321  * This default converter will accept only POSIX file names with pure ASCII
0322  * characters. This largely corresponds to the file name handling before the
0323  * optional UTF-8 support was added to the RTEMS implementation of the FAT file
0324  * system.  This handling is mostly backwards compatible to the previous RTEMS
0325  * implementation of the FAT file system.
0326  *
0327  * For backwards compatibility and the previous RTEMS implementation of the FAT
0328  * file system please see also @ref rtems_dosfs_mount_options and mount().
0329  *
0330  * @retval NULL Something failed.
0331  * @retval other Pointer to initialized converter.
0332  */
0333 rtems_dosfs_convert_control *rtems_dosfs_create_default_converter(void);
0334 
0335 /**
0336  * @brief Allocates and initializes a UTF-8 converter.
0337  *
0338  * This converter will assume that all file names passed to POSIX file handling
0339  * methods are UTF-8 strings and will convert them to the selected code page
0340  * for short file names and to UTF-16 for long file names.  This conversion
0341  * will be done during reading and writing.  These conversions correspond to
0342  * the specification of the FAT file system.  This handling is mostly backwards
0343  * compatible to the previous RTEMS implementation of the FAT file system.
0344  *
0345  * For backwards compatibility and the previous RTEMS implementation of the FAT
0346  * file system please see also @ref rtems_dosfs_mount_options and mount().
0347  *
0348  * One possible issue with this converter is: When reading file names which
0349  * have been created with other implementations of the FAT file system, it can
0350  * happen that during the conversion to UTF-8 a long file name becomes longer
0351  * and exceeds the 255 bytes limit.  In such a case only the short file name
0352  * will get read.
0353  *
0354  * @param[in] codepage The iconv() identification string for the used code
0355  * page.
0356  *
0357  * @retval NULL Something failed.
0358  * @retval other Pointer to initialized converter.
0359  */
0360 rtems_dosfs_convert_control *rtems_dosfs_create_utf8_converter(
0361   const char *codepage
0362 );
0363 
0364 #define MSDOS_FMT_INFO_LEVEL_NONE   (0)
0365 #define MSDOS_FMT_INFO_LEVEL_INFO   (1)
0366 #define MSDOS_FMT_INFO_LEVEL_DETAIL (2)
0367 #define MSDOS_FMT_INFO_LEVEL_DEBUG  (3)
0368 
0369 /**
0370  * @brief FAT file system format request parameters.
0371  */
0372 typedef struct {
0373   /**
0374    * @brief OEM name string or NULL.
0375    */
0376   const char *OEMName;
0377 
0378   /**
0379    * @brief Volume label string or NULL.
0380    */
0381   const char *VolLabel;
0382 
0383   /**
0384    * @brief Sectors per cluster hint.
0385    *
0386    * The format procedure may choose another value.  Use 0 as default value.
0387    */
0388   uint32_t sectors_per_cluster;
0389 
0390   /**
0391    * @brief Number of FATs hint.
0392    *
0393    * Use 0 as default value.
0394    */
0395   uint32_t fat_num;
0396 
0397   /**
0398    * @brief Minimum files in root directory for FAT12 and FAT16.
0399    *
0400    * The format procedure may choose a greater value.  Use 0 as default value.
0401    */
0402   uint32_t files_per_root_dir;
0403 
0404   /**
0405    * @brief Media code.
0406    *
0407    * Use 0 as default value.  The default media code is 0xf8.
0408    */
0409   uint8_t media;
0410 
0411   /**
0412    * @brief Quick format.
0413    *
0414    * If set to true, then do not clear data sectors to zero.
0415    */
0416   bool quick_format;
0417 
0418   /**
0419    * @brief Do not align FAT, data cluster, and root directory to a cluster
0420    * boundary.
0421    */
0422   bool skip_alignment;
0423 
0424   /**
0425    * @brief Synchronize device after write operations.
0426    */
0427   bool sync_device;
0428 
0429   /**
0430    * @brief The amount of info to output.
0431    */
0432   int info_level;
0433 } msdos_format_request_param_t;
0434 
0435 /**
0436  * @brief Formats a block device with a FAT file system.
0437  *
0438  * @param[in] devname The block device path.
0439  * @param[in] rqdata The FAT file system format request data.  Use NULL for
0440  * default parameters.
0441  *
0442  * @retval 0 Successful operation.
0443  * @retval -1 An error occurred.  The @c errno indicates the error.
0444  */
0445 int msdos_format (
0446   const char *devname,
0447   const msdos_format_request_param_t *rqdata
0448 );
0449 
0450 /** @} */
0451 
0452 int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry,
0453                            const void                           *data);
0454 
0455 #ifdef __cplusplus
0456 }
0457 #endif
0458 
0459 #endif