File indexing completed on 2025-05-11 08:24:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031 #ifdef HAVE_CONFIG_H
0032 #include "config.h"
0033 #endif
0034
0035 #include <ctype.h>
0036 #include <rtems.h>
0037 #include "msdos.h"
0038
0039
0040 #define SECONDSPERDAY ((uint32_t) 86400)
0041
0042 #define UTF8_MAX_CHAR_SIZE 4
0043 #define UTF8_NULL 0x00
0044 #define UTF8_NULL_SIZE 1
0045 #define UTF8_BLANK 0x20
0046 #define UTF8_BLANK_SIZE 1
0047 #define UTF8_FULL_STOP 0x2e
0048 #define UTF8_FULL_STOP_SIZE 1
0049
0050 #define UTF16_MAX_CHAR_SIZE 4
0051 #define UTF16_NULL CT_LE_W( 0x0000 )
0052 #define UTF16_NULL_SIZE 2
0053 #define UTF16_BLANK CT_LE_W( 0x0020 )
0054 #define UTF16_BLANK_SIZE 2
0055 #define UTF16_FULL_STOP CT_LE_W( 0x002e )
0056 #define UTF16_FULL_STOP_SIZE 2
0057
0058
0059
0060
0061 static uint16_t regyear[] = {
0062 31, 28, 31, 30, 31, 30,
0063 31, 31, 30, 31, 30, 31
0064 };
0065
0066
0067
0068
0069 static uint16_t leapyear[] = {
0070 31, 29, 31, 30, 31, 30,
0071 31, 31, 30, 31, 30, 31
0072 };
0073
0074
0075
0076
0077
0078 static uint32_t lasttime;
0079 static uint32_t lastday;
0080 static uint16_t lastddate;
0081 static uint16_t lastdtime;
0082
0083
0084
0085
0086
0087 void
0088 msdos_date_unix2dos(unsigned int t, uint16_t *ddp,
0089 uint16_t *dtp)
0090 {
0091 uint32_t days;
0092 uint32_t inc;
0093 uint32_t year;
0094 uint32_t month;
0095 uint16_t *months;
0096
0097
0098
0099
0100
0101 if (lasttime != t) {
0102 lasttime = t;
0103 lastdtime = (((t % 60) >> 1) << MSDOS_DT_2SECONDS_SHIFT)
0104 + (((t / 60) % 60) << MSDOS_DT_MINUTES_SHIFT)
0105 + (((t / 3600) % 24) << MSDOS_DT_HOURS_SHIFT);
0106
0107
0108
0109
0110
0111
0112 days = t / (SECONDSPERDAY);
0113 if (days != lastday) {
0114 lastday = days;
0115 for (year = 1970;; year++) {
0116 inc = year & 0x03 ? 365 : 366;
0117 if (days < inc)
0118 break;
0119 days -= inc;
0120 }
0121 months = year & 0x03 ? regyear : leapyear;
0122 for (month = 0; month < 12; month++) {
0123 if (days < months[month])
0124 break;
0125 days -= months[month];
0126 }
0127 lastddate = ((days + 1) << MSDOS_DD_DAY_SHIFT)
0128 + ((month + 1) << MSDOS_DD_MONTH_SHIFT);
0129
0130
0131
0132
0133
0134
0135 if (year > 1980)
0136 lastddate += (year - 1980) <<
0137 MSDOS_DD_YEAR_SHIFT;
0138 }
0139 }
0140 *dtp = lastdtime;
0141 *ddp = lastddate;
0142 }
0143
0144
0145
0146
0147
0148
0149 #define DAYSTO1980 ((uint32_t) 3652)
0150
0151 static uint16_t lastdosdate;
0152 static uint32_t lastseconds;
0153
0154
0155
0156
0157
0158
0159 unsigned int
0160 msdos_date_dos2unix(unsigned int dd, unsigned int dt)
0161 {
0162 uint32_t seconds;
0163 uint32_t m, month;
0164 uint32_t y, year;
0165 uint32_t days;
0166 uint16_t *months;
0167
0168 seconds = 2 * ((dt & MSDOS_DT_2SECONDS_MASK) >> MSDOS_DT_2SECONDS_SHIFT)
0169 + ((dt & MSDOS_DT_MINUTES_MASK) >> MSDOS_DT_MINUTES_SHIFT) * 60
0170 + ((dt & MSDOS_DT_HOURS_MASK) >> MSDOS_DT_HOURS_SHIFT) * 3600;
0171
0172
0173
0174
0175 if (lastdosdate != dd) {
0176 lastdosdate = dd;
0177 days = 0;
0178 year = (dd & MSDOS_DD_YEAR_MASK) >> MSDOS_DD_YEAR_SHIFT;
0179 for (y = 0; y < year; y++)
0180 days += y & 0x03 ? 365 : 366;
0181 months = year & 0x03 ? regyear : leapyear;
0182
0183
0184
0185
0186 month = (dd & MSDOS_DD_MONTH_MASK) >> MSDOS_DD_MONTH_SHIFT;
0187 if (month == 0) {
0188 month = 1;
0189 }
0190 for (m = 0; m < month - 1; m++)
0191 days += months[m];
0192 days += ((dd & MSDOS_DD_DAY_MASK) >> MSDOS_DD_DAY_SHIFT) - 1;
0193 lastseconds = (days + DAYSTO1980) * SECONDSPERDAY;
0194 }
0195 return seconds + lastseconds;
0196 }
0197
0198
0199 static const uint8_t codepage_valid_char_map[] = {
0200 0, 0, 0, 0, 0, 0, 0, 0,
0201 0, 0, 0, 0, 0, 0, 0, 0,
0202 0, 0, 0, 0, 0, 0, 0, 0,
0203 0, 0, 0, 0, 0, 0, 0, 0,
0204 0x20, 0x21, 0, 0x23, 0x24, 0x25, 0x26, 0x27,
0205 0x28, 0x29, 0, 0, 0, 0x2d, 0, 0,
0206 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0207 0x38, 0x39, 0, 0, 0, 0, 0, 0,
0208 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
0209 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
0210 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
0211 0x58, 0x59, 0x5a, 0, 0, 0, 0x5e, 0x5f,
0212 0x60, 0, 0, 0, 0, 0, 0, 0,
0213 0, 0, 0, 0, 0, 0, 0, 0,
0214 0, 0, 0, 0, 0, 0, 0, 0,
0215 0, 0, 0, 0x7b, 0, 0x7d, 0x7e, 0,
0216 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0217 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0218 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0219 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0220 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0221 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0222 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0223 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0224 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0225 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0226 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0227 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0228 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0229 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0230 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0231 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
0232 };
0233
0234 static uint16_t
0235 msdos_get_valid_utf16_filename_character (const uint16_t utf16_character)
0236 {
0237 uint16_t retval = 0x0000;
0238 uint16_t char_num = CF_LE_W( utf16_character );
0239
0240 if ( char_num <= 0x00ff ) {
0241 switch ( char_num )
0242 {
0243 case 0x002b:
0244 case 0x002c:
0245 case 0x002e:
0246 case 0x003b:
0247 case 0x003d:
0248 case 0x005b:
0249 case 0x005d:
0250 case 0x0061:
0251 case 0x0062:
0252 case 0x0063:
0253 case 0x0064:
0254 case 0x0065:
0255 case 0x0066:
0256 case 0x0067:
0257 case 0x0068:
0258 case 0x0069:
0259 case 0x006a:
0260 case 0x006b:
0261 case 0x006c:
0262 case 0x006d:
0263 case 0x006e:
0264 case 0x006f:
0265 case 0x0070:
0266 case 0x0071:
0267 case 0x0072:
0268 case 0x0073:
0269 case 0x0074:
0270 case 0x0075:
0271 case 0x0076:
0272 case 0x0077:
0273 case 0x0078:
0274 case 0x0079:
0275 case 0x007a:
0276 retval = char_num;
0277 break;
0278 default:
0279 retval = codepage_valid_char_map[char_num];
0280 break;
0281 }
0282 }
0283 else
0284 retval = char_num;
0285
0286 return CT_LE_W( retval );
0287 }
0288
0289 static char
0290 msdos_get_valid_codepage_filename_character (const uint8_t character)
0291 {
0292 char c = codepage_valid_char_map[character];
0293
0294 if (c == 0) {
0295 c = '_';
0296 }
0297
0298 return c;
0299 }
0300
0301 static ssize_t
0302 msdos_filename_process_dot_names (const uint8_t *src_name,
0303 const size_t src_size,
0304 uint8_t *dest_name,
0305 const size_t dest_size)
0306 {
0307 ssize_t returned_size = 0;
0308 int eno = 0;
0309
0310
0311
0312
0313 if ( src_name[0] == UTF8_FULL_STOP
0314 && src_size == UTF8_FULL_STOP_SIZE) {
0315 if (dest_size >= UTF8_FULL_STOP_SIZE) {
0316 dest_name[0] = UTF8_FULL_STOP;
0317 returned_size = UTF8_FULL_STOP_SIZE;
0318 }
0319 else
0320 eno = ENAMETOOLONG;
0321 }
0322 else if ( eno == 0
0323 && src_name[0] == UTF8_FULL_STOP
0324 && src_name[1] == UTF8_FULL_STOP
0325 && src_size == ( 2 * UTF8_FULL_STOP_SIZE ) ) {
0326 if (dest_size >= 2 * UTF8_FULL_STOP_SIZE) {
0327 dest_name[0] = UTF8_FULL_STOP;
0328 dest_name[1] = UTF8_FULL_STOP;
0329 returned_size = 2 * UTF8_FULL_STOP_SIZE;
0330 }
0331 else
0332 eno = ENAMETOOLONG;
0333 }
0334
0335 if (eno != 0) {
0336 errno = eno;
0337 returned_size = -1;
0338 }
0339
0340 return returned_size;
0341 }
0342
0343 static ssize_t
0344 msdos_filename_delete_trailing_dots (const uint8_t *filename_utf8,
0345 const size_t filename_size)
0346 {
0347 ssize_t size_returned = filename_size;
0348 unsigned int i;
0349
0350
0351
0352
0353 for ( i = size_returned - UTF8_FULL_STOP_SIZE;
0354 size_returned >= UTF8_FULL_STOP_SIZE
0355 && filename_utf8[i] == UTF8_FULL_STOP;) {
0356 size_returned -= UTF8_FULL_STOP_SIZE;
0357 i -= UTF8_FULL_STOP_SIZE;
0358 }
0359
0360 return size_returned;
0361 }
0362
0363 ssize_t
0364 msdos_filename_utf8_to_long_name_for_compare (
0365 rtems_dosfs_convert_control *converter,
0366 const uint8_t *utf8_name,
0367 const size_t utf8_name_size,
0368 uint8_t *long_name,
0369 const size_t long_name_size)
0370 {
0371 ssize_t returned_size = 0;
0372 int eno = 0;
0373 size_t name_size;
0374 size_t dest_size = long_name_size;
0375
0376 returned_size = msdos_filename_process_dot_names (
0377 utf8_name,
0378 utf8_name_size,
0379 long_name,
0380 long_name_size);
0381
0382 if (returned_size == 0) {
0383 name_size = msdos_filename_delete_trailing_dots (
0384 &utf8_name[0],
0385 utf8_name_size);
0386 if (name_size > 0) {
0387 eno = (*converter->handler->utf8_normalize_and_fold) (
0388 converter,
0389 utf8_name,
0390 name_size,
0391 long_name,
0392 &dest_size);
0393 if (eno == 0) {
0394 returned_size = (ssize_t)dest_size;
0395 }
0396 } else {
0397 eno = EINVAL;
0398 }
0399 }
0400
0401 if ( eno != 0 ) {
0402 errno = eno;
0403 returned_size = -1;
0404 }
0405
0406 return returned_size;
0407 }
0408
0409 ssize_t
0410 msdos_filename_utf8_to_long_name_for_save (
0411 rtems_dosfs_convert_control *converter,
0412 const uint8_t *utf8_name,
0413 const size_t utf8_name_size,
0414 uint16_t *long_name,
0415 const size_t long_name_size)
0416 {
0417 ssize_t returned_size = 0;
0418 int eno = 0;
0419 size_t name_size;
0420 size_t name_size_tmp;
0421 int i;
0422 uint16_t c;
0423 unsigned int chars_written;
0424
0425 name_size_tmp = long_name_size;
0426 name_size = msdos_filename_delete_trailing_dots (
0427 &utf8_name[0],
0428 utf8_name_size);
0429 if (name_size > 0) {
0430
0431
0432
0433 eno = (*converter->handler->utf8_to_utf16) (
0434 converter,
0435 utf8_name,
0436 name_size,
0437 &long_name[0],
0438 &name_size_tmp);
0439 if (eno == 0) {
0440 if (name_size_tmp <= (MSDOS_NAME_MAX_LNF_LEN * MSDOS_NAME_LFN_BYTES_PER_CHAR))
0441 name_size = name_size_tmp;
0442 else
0443 eno = ENAMETOOLONG;
0444 }
0445
0446 if ( eno == 0 )
0447 {
0448
0449
0450
0451 for ( i = 0;
0452 name_size
0453 && (c = msdos_get_valid_utf16_filename_character ( long_name[i]) );
0454 ++i ) {
0455 long_name[i] = c;
0456 returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
0457 name_size -= MSDOS_NAME_LFN_BYTES_PER_CHAR;
0458 }
0459 if ( name_size == UTF16_NULL_SIZE && c == UTF16_NULL ) {
0460 long_name[i] = c;
0461 returned_size += MSDOS_NAME_LFN_BYTES_PER_CHAR;
0462 }
0463 else if ( name_size != 0 )
0464 eno = EINVAL;
0465 chars_written = returned_size / MSDOS_NAME_LFN_BYTES_PER_CHAR;
0466 if ( long_name [chars_written - 1] != UTF16_NULL
0467 && (returned_size + UTF16_NULL_SIZE ) <= long_name_size ) {
0468 long_name[chars_written] = UTF16_NULL;
0469 }
0470 }
0471 }
0472 else
0473 eno = EINVAL;
0474
0475 if ( eno != 0 ) {
0476 errno = eno;
0477 returned_size = -1;
0478 }
0479
0480 return returned_size;
0481 }
0482
0483
0484
0485
0486 static void msdos_filename_remove_prepended_dots (const uint8_t **name_utf8,
0487 size_t *name_size)
0488 {
0489 while ( *name_size >= UTF8_FULL_STOP_SIZE
0490 && **name_utf8 == UTF8_FULL_STOP) {
0491 *name_utf8 += UTF8_FULL_STOP_SIZE;
0492 *name_size -= UTF8_FULL_STOP_SIZE;
0493 }
0494 }
0495
0496 ssize_t
0497 msdos_filename_utf8_to_short_name_for_compare (
0498 rtems_dosfs_convert_control *converter,
0499 const uint8_t *utf8_name,
0500 const size_t utf8_name_size,
0501 void *short_name,
0502 const size_t short_name_size)
0503 {
0504 ssize_t returned_size = 0;
0505 int eno = 0;
0506 const uint8_t *name_ptr = utf8_name;
0507 char *dest_ptr = (char*)short_name;
0508 size_t name_size = utf8_name_size;
0509 uint8_t name_normalized_buf[(MSDOS_SHORT_NAME_LEN +1) * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR];
0510 size_t name_size_tmp = sizeof(name_normalized_buf);
0511
0512 returned_size = msdos_filename_process_dot_names (
0513 utf8_name,
0514 utf8_name_size,
0515 short_name,
0516 short_name_size);
0517
0518 if (returned_size == 0) {
0519 msdos_filename_remove_prepended_dots (&name_ptr,
0520 &name_size);
0521 if (name_size > 0) {
0522
0523
0524
0525 eno = (*converter->handler->utf8_normalize_and_fold) (
0526 converter,
0527 name_ptr,
0528 name_size,
0529 &name_normalized_buf[0],
0530 &name_size_tmp);
0531 name_ptr = &name_normalized_buf[0];
0532 name_size = name_size_tmp;
0533 if ( eno == ENOMEM ) {
0534 eno = 0;
0535 }
0536 if ( eno == 0 ) {
0537 memcpy (&dest_ptr[0], &name_ptr[0], name_size);
0538 returned_size = name_size;
0539 }
0540 } else
0541 eno = EINVAL;
0542 }
0543
0544 if ( eno != 0 ) {
0545 errno = eno;
0546 returned_size = -1;
0547 }
0548
0549 return returned_size;
0550 }
0551
0552 ssize_t
0553 msdos_filename_utf8_to_short_name_for_save (
0554 rtems_dosfs_convert_control *converter,
0555 const uint8_t *utf8_name,
0556 const size_t utf8_name_size,
0557 void *short_name,
0558 const size_t short_name_size)
0559 {
0560 ssize_t returned_size = 0;
0561 int eno = 0;
0562 const uint8_t *name_ptr = utf8_name;
0563 size_t name_size = utf8_name_size;
0564 char *dest_ptr = (char*)short_name;
0565 unsigned int i;
0566 size_t name_size_tmp;
0567 char name_to_format_buf[MSDOS_SHORT_NAME_LEN +1];
0568
0569 returned_size = msdos_filename_process_dot_names (
0570 utf8_name,
0571 utf8_name_size,
0572 short_name,
0573 short_name_size);
0574
0575 if (returned_size == 0) {
0576 msdos_filename_remove_prepended_dots (&name_ptr,
0577 &name_size);
0578
0579 if (name_size > 0) {
0580
0581
0582
0583 name_size_tmp = sizeof ( name_to_format_buf );
0584 eno = (*converter->handler->utf8_to_codepage) (
0585 converter,
0586 name_ptr,
0587 name_size,
0588 &name_to_format_buf[0],
0589 &name_size_tmp);
0590 if ( eno != 0 ) {
0591
0592
0593
0594
0595
0596
0597
0598 eno = 0;
0599 }
0600 name_ptr = (const uint8_t *)(&name_to_format_buf[0]);
0601 name_size = name_size_tmp;
0602 for (i = 0; i < name_size; ++i)
0603 name_to_format_buf[i] = toupper ( (unsigned char)(name_to_format_buf[i]) );
0604
0605
0606
0607 if ( name_size > 0 ) {
0608
0609
0610
0611 if ( 0x20 == *name_ptr )
0612 dest_ptr[0] = '_';
0613 else if ( 0xE5 == *name_ptr )
0614 dest_ptr[0] = 0x05;
0615 else
0616 dest_ptr[0] = msdos_get_valid_codepage_filename_character(*name_ptr);
0617 ++name_ptr;
0618 ++returned_size;
0619 --name_size;
0620
0621
0622
0623 for (i = 1; i <= 7 && name_size && *name_ptr != '.'; ++i) {
0624 dest_ptr[i] = msdos_get_valid_codepage_filename_character(*name_ptr);
0625 ++name_ptr;
0626 ++returned_size;
0627 --name_size;
0628 }
0629
0630
0631
0632
0633 if ( name_size > 0 && *name_ptr == '.' ) {
0634 ++name_ptr;
0635 --name_size;
0636 }
0637
0638 for (; i < 8; ++i) {
0639 dest_ptr[i] = ' ';
0640 ++returned_size;
0641 }
0642
0643
0644
0645
0646 for (; i <= 10 && name_size ; i++) {
0647 dest_ptr[i] = msdos_get_valid_codepage_filename_character(*name_ptr);
0648 ++name_ptr;
0649 ++returned_size;
0650 name_size--;
0651 }
0652
0653
0654
0655 for ( ; i < short_name_size; ++i ) {
0656 dest_ptr[i] = ' ';
0657 ++returned_size;
0658 }
0659 }
0660 }
0661 else
0662 eno = EINVAL;
0663 }
0664
0665 if ( eno != 0 ) {
0666 errno = eno;
0667 return -1;
0668 }
0669
0670 return returned_size;
0671 }
0672
0673