[a3f1b54] | 1 | /** |
---|
[d2e0bb3] | 2 | * @file |
---|
[f36a7bfc] | 3 | * |
---|
[d2e0bb3] | 4 | * @brief Application Interface to FAT Filesystem |
---|
[2305f97] | 5 | * |
---|
[d2e0bb3] | 6 | * @ingroup DOSFS |
---|
[a3f1b54] | 7 | */ |
---|
[0a7278e] | 8 | |
---|
[a3f1b54] | 9 | /* |
---|
[f36a7bfc] | 10 | * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia |
---|
| 11 | * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru> |
---|
| 12 | * |
---|
[d2e0bb3] | 13 | * Modifications to support UTF-8 in the file system are |
---|
| 14 | * Copyright (c) 2013 embedded brains GmbH. |
---|
| 15 | * |
---|
[f36a7bfc] | 16 | * The license and distribution terms for this file may be |
---|
| 17 | * found in the file LICENSE in this distribution or at |
---|
[c499856] | 18 | * http://www.rtems.org/license/LICENSE. |
---|
[f36a7bfc] | 19 | */ |
---|
[0a7278e] | 20 | |
---|
[a6f5d89] | 21 | #ifndef _RTEMS_DOSFS_H |
---|
| 22 | #define _RTEMS_DOSFS_H |
---|
[f36a7bfc] | 23 | |
---|
[0a896eb] | 24 | #include <rtems.h> |
---|
| 25 | #include <rtems/libio.h> |
---|
| 26 | |
---|
[f36a7bfc] | 27 | #ifdef __cplusplus |
---|
| 28 | extern "C" { |
---|
| 29 | #endif |
---|
| 30 | |
---|
[d2e0bb3] | 31 | typedef struct rtems_dosfs_convert_control rtems_dosfs_convert_control; |
---|
| 32 | |
---|
| 33 | /** |
---|
| 34 | * @brief Converts from UTF-8 into a specific code page. |
---|
| 35 | * |
---|
[961669d] | 36 | * @param[in,out] self The convert control. |
---|
[d2e0bb3] | 37 | * @param[in] src A well-formed UTF-8 string to be converted. |
---|
[cc69334f] | 38 | * @param[in] src_size The size of the string in bytes (inludes '\\0' if any). |
---|
[d2e0bb3] | 39 | * @param[out] dst The address the converted string will get copied to. |
---|
[961669d] | 40 | * @param[in,out] dst_size The size of the buffer in bytes respectively the |
---|
[d2e0bb3] | 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 | */ |
---|
| 47 | typedef 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 | * |
---|
[961669d] | 58 | * @param[in,out] self The convert control. |
---|
[d2e0bb3] | 59 | * @param[in] src A well-formed string in code page format. |
---|
[cc69334f] | 60 | * @param[in] src_size The size of the string in bytes (inludes '\\0' if any). |
---|
[d2e0bb3] | 61 | * @param[out] dst The address the converted string will get copied to. |
---|
[961669d] | 62 | * @param[in,out] dst_size The size of the buffer in bytes respectively the |
---|
[d2e0bb3] | 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 | */ |
---|
| 69 | typedef 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 | * |
---|
[961669d] | 80 | * @param[in,out] self The convert control. |
---|
[d2e0bb3] | 81 | * @param[in] src A well-formed UTF-8 string to be converted. |
---|
[cc69334f] | 82 | * @param[in] src_size The size of the string in bytes (inludes '\\0' if any). |
---|
[d2e0bb3] | 83 | * @param[out] dst The address the converted string will get copied to |
---|
[961669d] | 84 | * @param[in,out] dst_size The size of the buffer in bytes respectively the |
---|
[d2e0bb3] | 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 | */ |
---|
| 91 | typedef 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 | * |
---|
[961669d] | 102 | * @param[in,out] self The convert control. |
---|
[d2e0bb3] | 103 | * @param[in] src A well-formed UTF-16 string to be converted. |
---|
[cc69334f] | 104 | * @param[in] src_size The size of the string in bytes (inludes '\\0' if any). |
---|
[d2e0bb3] | 105 | * @param[out] dst The address the converted string will get copied to. |
---|
[961669d] | 106 | * @param[in,out] dst_size The size of the buffer in bytes respectively the |
---|
[d2e0bb3] | 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 | */ |
---|
| 113 | typedef 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 | * |
---|
[961669d] | 127 | * @param[in,out] self The convert control. |
---|
[d2e0bb3] | 128 | * @param[in] src A well-formed UTF-8 string to be normalized and fold. |
---|
[cc69334f] | 129 | * @param[in] src_size The size of the string in bytes (inludes '\\0' if any). |
---|
[d2e0bb3] | 130 | * @param[out] dst The address the normalized and fold string will get |
---|
| 131 | * copied to. |
---|
[961669d] | 132 | * @param[in,out] dst_size The size of the buffer in bytes respectively the |
---|
[d2e0bb3] | 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 | */ |
---|
| 141 | typedef 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 | * |
---|
[961669d] | 152 | * @param[in,out] self The convert control for destruction. |
---|
[d2e0bb3] | 153 | */ |
---|
| 154 | typedef void (*rtems_dosfs_convert_destroy)( |
---|
| 155 | rtems_dosfs_convert_control *self |
---|
| 156 | ); |
---|
| 157 | |
---|
| 158 | /** |
---|
| 159 | * @brief FAT filesystem convert handler. |
---|
| 160 | */ |
---|
| 161 | typedef 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 | |
---|
| 170 | typedef 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 | */ |
---|
| 182 | struct 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 | * |
---|
[9bfd7ff] | 192 | * @brief FAT file system configuration support, format and mount options. |
---|
| 193 | * |
---|
| 194 | * A block device can be formatted with a FAT file system with the |
---|
| 195 | * msdos_format() function. |
---|
| 196 | * |
---|
| 197 | * The FAT file system mount operation can be controlled with FAT file system |
---|
| 198 | * specific mount options, see @ref rtems_dosfs_mount_options. |
---|
| 199 | * |
---|
[d2e0bb3] | 200 | * @{ |
---|
| 201 | */ |
---|
| 202 | |
---|
[e67025e] | 203 | /** |
---|
| 204 | * @brief Semaphore count per FAT filesystem instance. |
---|
| 205 | * |
---|
| 206 | * This can be used for system configuration via <rtems/confdefs.h>. |
---|
| 207 | */ |
---|
| 208 | #define RTEMS_DOSFS_SEMAPHORES_PER_INSTANCE 1 |
---|
| 209 | |
---|
[d2e0bb3] | 210 | /** |
---|
| 211 | * @brief FAT filesystem mount options. |
---|
| 212 | */ |
---|
| 213 | typedef struct { |
---|
| 214 | /** |
---|
[27170bae] | 215 | * @brief Converter implementation for new file system instance. |
---|
| 216 | * |
---|
| 217 | * Before converters have been added to the RTEMS implementation of the FAT |
---|
| 218 | * file system, the implementation was: |
---|
| 219 | * - Short names were saved in code page format (as is still the case). |
---|
| 220 | * - Long names were not saved in UTF-16 format as mandated by the FAT file |
---|
| 221 | * system specification. Instead the character in the local encoding was |
---|
| 222 | * stored to the low byte directly and the high byte was set to zero. |
---|
| 223 | * |
---|
| 224 | * There are a few compatibility issues due to a non-standard conform |
---|
| 225 | * implementation of the FAT file system before the UTF-8 support was added. |
---|
| 226 | * These following issues affect the default converter and the UTF-8 |
---|
| 227 | * converter: |
---|
| 228 | * - Before UTF-8 support was added, it was possible to create files with the |
---|
| 229 | * the same short name in single case and mixed case in a directory. It |
---|
| 230 | * was for example possible to have files "ABC" and "aBc" in a single |
---|
| 231 | * directory. Now this bug is fixed. |
---|
| 232 | * - Before UTF-8 support was added, it was possible to create files with a |
---|
| 233 | * name length of slightly more than 255 characters. Now the |
---|
| 234 | * implementation adheres exactly to the 255 character limit. |
---|
| 235 | * - Long file names saved before UTF-8 support was added could contain |
---|
| 236 | * non-ASCII characters in the low byte which was saved for a long name |
---|
| 237 | * character. With the default converter this means such files can be read |
---|
| 238 | * only by their short file name. With the UTF-8 converter file names will |
---|
| 239 | * be read correctly as long as the characters written with the old |
---|
| 240 | * implementation were Latin-1 characters. |
---|
| 241 | * |
---|
| 242 | * The following sample code demonstrates how to mount a file |
---|
| 243 | * system with UTF-8 support: |
---|
| 244 | * @code |
---|
| 245 | * #include <errno.h> |
---|
| 246 | * #include <assert.h> |
---|
| 247 | * #include <rtems/dosfs.h> |
---|
| 248 | * #include <rtems/libio.h> |
---|
| 249 | * |
---|
| 250 | * static int mount_with_utf8( |
---|
| 251 | * const char *device_file, |
---|
| 252 | * const char *mount_point |
---|
| 253 | * ) |
---|
| 254 | * { |
---|
| 255 | * rtems_dosfs_convert_control *convert_ctrl; |
---|
| 256 | * int rv; |
---|
| 257 | * |
---|
| 258 | * convert_ctrl = rtems_dosfs_create_utf8_converter( "CP850" ); |
---|
| 259 | * |
---|
| 260 | * if ( convert_ctrl != NULL ) { |
---|
| 261 | * rtems_dosfs_mount_options mount_opts; |
---|
| 262 | * |
---|
| 263 | * memset( &mount_opts, 0, sizeof( mount_opts ) ); |
---|
| 264 | * mount_opts.converter = convert_ctrl; |
---|
| 265 | * |
---|
| 266 | * rv = mount_and_make_target_path( |
---|
| 267 | * device_file, |
---|
| 268 | * mount_point, |
---|
| 269 | * RTEMS_FILESYSTEM_TYPE_DOSFS, |
---|
| 270 | * RTEMS_FILESYSTEM_READ_WRITE, |
---|
| 271 | * &mount_opts |
---|
| 272 | * ); |
---|
| 273 | * } else { |
---|
| 274 | * rv = -1; |
---|
| 275 | * errno = ENOMEM; |
---|
| 276 | * } |
---|
| 277 | * |
---|
| 278 | * return rv; |
---|
| 279 | * } |
---|
| 280 | * @endcode |
---|
| 281 | * |
---|
| 282 | * In case you do not want UTF-8 support, you can simply pass a NULL pointer |
---|
| 283 | * to mount_and_make_target_path() respectively to mount() instead of the |
---|
| 284 | * mount_opts address. |
---|
[d2e0bb3] | 285 | * |
---|
[83a4cbb] | 286 | * @see rtems_dosfs_create_default_converter() and |
---|
| 287 | * rtems_dosfs_create_utf8_converter(). |
---|
[d2e0bb3] | 288 | */ |
---|
| 289 | rtems_dosfs_convert_control *converter; |
---|
| 290 | } rtems_dosfs_mount_options; |
---|
[f36a7bfc] | 291 | |
---|
[697cf9df] | 292 | /** |
---|
[d2e0bb3] | 293 | * @brief Allocates and initializes a default converter. |
---|
[697cf9df] | 294 | * |
---|
[27170bae] | 295 | * This default converter will accept only POSIX file names with pure ASCII |
---|
| 296 | * characters. This largely corresponds to the file name handling before the |
---|
| 297 | * optional UTF-8 support was added to the RTEMS implementation of the FAT file |
---|
| 298 | * system. This handling is mostly backwards compatible to the previous RTEMS |
---|
| 299 | * implementation of the FAT file system. |
---|
| 300 | * |
---|
| 301 | * For backwards compatibility and the previous RTEMS implementation of the FAT |
---|
| 302 | * file system please see also @ref rtems_dosfs_mount_options and mount(). |
---|
| 303 | * |
---|
[d2e0bb3] | 304 | * @retval NULL Something failed. |
---|
| 305 | * @retval other Pointer to initialized converter. |
---|
[697cf9df] | 306 | */ |
---|
[d2e0bb3] | 307 | rtems_dosfs_convert_control *rtems_dosfs_create_default_converter(void); |
---|
[697cf9df] | 308 | |
---|
[83a4cbb] | 309 | /** |
---|
| 310 | * @brief Allocates and initializes a UTF-8 converter. |
---|
| 311 | * |
---|
[27170bae] | 312 | * This converter will assume that all file names passed to POSIX file handling |
---|
| 313 | * methods are UTF-8 strings and will convert them to the selected code page |
---|
| 314 | * for short file names and to UTF-16 for long file names. This conversion |
---|
| 315 | * will be done during reading and writing. These conversions correspond to |
---|
| 316 | * the specification of the FAT file system. This handling is mostly backwards |
---|
| 317 | * compatible to the previous RTEMS implementation of the FAT file system. |
---|
| 318 | * |
---|
| 319 | * For backwards compatibility and the previous RTEMS implementation of the FAT |
---|
| 320 | * file system please see also @ref rtems_dosfs_mount_options and mount(). |
---|
| 321 | * |
---|
| 322 | * One possible issue with this converter is: When reading file names which |
---|
| 323 | * have been created with other implementations of the FAT file system, it can |
---|
| 324 | * happen that during the conversion to UTF-8 a long file name becomes longer |
---|
| 325 | * and exceeds the 255 bytes limit. In such a case only the short file name |
---|
| 326 | * will get read. |
---|
| 327 | * |
---|
| 328 | * @param[in] codepage The iconv() identification string for the used code |
---|
| 329 | * page. |
---|
[83a4cbb] | 330 | * |
---|
| 331 | * @retval NULL Something failed. |
---|
| 332 | * @retval other Pointer to initialized converter. |
---|
| 333 | */ |
---|
| 334 | rtems_dosfs_convert_control *rtems_dosfs_create_utf8_converter( |
---|
| 335 | const char *codepage |
---|
| 336 | ); |
---|
| 337 | |
---|
[07d6fd5] | 338 | #define MSDOS_FMT_INFO_LEVEL_NONE (0) |
---|
| 339 | #define MSDOS_FMT_INFO_LEVEL_INFO (1) |
---|
| 340 | #define MSDOS_FMT_INFO_LEVEL_DETAIL (2) |
---|
| 341 | #define MSDOS_FMT_INFO_LEVEL_DEBUG (3) |
---|
| 342 | |
---|
[697cf9df] | 343 | /** |
---|
| 344 | * @brief FAT file system format request parameters. |
---|
[c36f885a] | 345 | */ |
---|
| 346 | typedef struct { |
---|
[697cf9df] | 347 | /** |
---|
| 348 | * @brief OEM name string or NULL. |
---|
| 349 | */ |
---|
| 350 | const char *OEMName; |
---|
| 351 | |
---|
| 352 | /** |
---|
| 353 | * @brief Volume label string or NULL. |
---|
| 354 | */ |
---|
| 355 | const char *VolLabel; |
---|
| 356 | |
---|
| 357 | /** |
---|
| 358 | * @brief Sectors per cluster hint. |
---|
| 359 | * |
---|
| 360 | * The format procedure may choose another value. Use 0 as default value. |
---|
| 361 | */ |
---|
| 362 | uint32_t sectors_per_cluster; |
---|
| 363 | |
---|
| 364 | /** |
---|
| 365 | * @brief Number of FATs hint. |
---|
| 366 | * |
---|
| 367 | * Use 0 as default value. |
---|
| 368 | */ |
---|
| 369 | uint32_t fat_num; |
---|
| 370 | |
---|
| 371 | /** |
---|
| 372 | * @brief Minimum files in root directory for FAT12 and FAT16. |
---|
| 373 | * |
---|
| 374 | * The format procedure may choose a greater value. Use 0 as default value. |
---|
| 375 | */ |
---|
| 376 | uint32_t files_per_root_dir; |
---|
| 377 | |
---|
| 378 | /** |
---|
| 379 | * @brief Media code. |
---|
| 380 | * |
---|
| 381 | * Use 0 as default value. The default media code is 0xf8. |
---|
| 382 | */ |
---|
| 383 | uint8_t media; |
---|
| 384 | |
---|
| 385 | /** |
---|
| 386 | * @brief Quick format. |
---|
| 387 | * |
---|
| 388 | * If set to true, then do not clear data sectors to zero. |
---|
| 389 | */ |
---|
| 390 | bool quick_format; |
---|
| 391 | |
---|
| 392 | /** |
---|
| 393 | * @brief Do not align FAT, data cluster, and root directory to a cluster |
---|
| 394 | * boundary. |
---|
| 395 | */ |
---|
| 396 | bool skip_alignment; |
---|
| 397 | |
---|
[4b8e01f] | 398 | /** |
---|
| 399 | * @brief Synchronize device after write operations. |
---|
| 400 | */ |
---|
| 401 | bool sync_device; |
---|
| 402 | |
---|
[697cf9df] | 403 | /** |
---|
| 404 | * @brief The amount of info to output. |
---|
| 405 | */ |
---|
| 406 | int info_level; |
---|
[c36f885a] | 407 | } msdos_format_request_param_t; |
---|
| 408 | |
---|
[697cf9df] | 409 | /** |
---|
| 410 | * @brief Formats a block device with a FAT file system. |
---|
| 411 | * |
---|
| 412 | * @param[in] devname The block device path. |
---|
| 413 | * @param[in] rqdata The FAT file system format request data. Use NULL for |
---|
| 414 | * default parameters. |
---|
| 415 | * |
---|
| 416 | * @retval 0 Successful operation. |
---|
| 417 | * @retval -1 An error occurred. The @c errno indicates the error. |
---|
| 418 | */ |
---|
| 419 | int msdos_format ( |
---|
| 420 | const char *devname, |
---|
| 421 | const msdos_format_request_param_t *rqdata |
---|
| 422 | ); |
---|
| 423 | |
---|
| 424 | /** @} */ |
---|
[c36f885a] | 425 | |
---|
[d2e0bb3] | 426 | int rtems_dosfs_initialize(rtems_filesystem_mount_table_entry_t *mt_entry, |
---|
| 427 | const void *data); |
---|
| 428 | |
---|
[f36a7bfc] | 429 | #ifdef __cplusplus |
---|
| 430 | } |
---|
| 431 | #endif |
---|
| 432 | |
---|
[a6f5d89] | 433 | #endif |
---|