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 #define MSDOS_TRACE 1
0022
0023 #ifdef HAVE_CONFIG_H
0024 #include "config.h"
0025 #endif
0026
0027 #include <stdlib.h>
0028 #include <ctype.h>
0029 #include <sys/time.h>
0030 #include <unistd.h>
0031 #include <string.h>
0032 #include <assert.h>
0033 #include <errno.h>
0034 #include <inttypes.h>
0035 #include <rtems/libio_.h>
0036
0037 #include "fat.h"
0038 #include "fat_fat_operations.h"
0039 #include "fat_file.h"
0040
0041 #include "msdos.h"
0042
0043
0044 #include <stdio.h>
0045
0046 #define MSDOS_LFN_ENTRY_SIZE \
0047 (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR)
0048
0049 #define MSDOS_LFN_ENTRY_SIZE_UTF8 \
0050 ((MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_LFN_BYTES_PER_CHAR \
0051 * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
0052
0053
0054
0055
0056 const char *const MSDOS_DOT_NAME = ". ";
0057 const char *const MSDOS_DOTDOT_NAME = ".. ";
0058
0059 uint8_t
0060 msdos_lfn_checksum(const void *entry)
0061 {
0062 const uint8_t *name;
0063 uint8_t cs;
0064 int i;
0065
0066 name = (const uint8_t *) MSDOS_DIR_NAME(entry);
0067 cs = 0;
0068
0069 for (i = 0; i < MSDOS_SHORT_NAME_LEN; ++i) {
0070 cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + name[i];
0071 }
0072
0073 return cs;
0074 }
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095 static msdos_name_type_t
0096 msdos_is_valid_name_char(const char ch)
0097 {
0098 if (strchr(" +,;=[]", ch) != NULL)
0099 return MSDOS_NAME_LONG;
0100
0101 if ((ch == '.') || isalnum((unsigned char)ch) ||
0102 (strchr("$%'-_@~`!(){}^#&", ch) != NULL) || (unsigned char) ch > 127)
0103 return MSDOS_NAME_SHORT;
0104
0105 return MSDOS_NAME_INVALID;
0106 }
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119 static void
0120 msdos_short_name_hex(char* sfn, uint32_t num)
0121 {
0122 static const char* hex = "0123456789ABCDEF";
0123 char* c = MSDOS_DIR_NAME(sfn);
0124 int i;
0125 for (i = 0; i < 2; i++, c++)
0126 if ((*c == ' ') || (*c == '.'))
0127 *c = '_';
0128 for (i = 0; i < 4; i++, c++)
0129 *c = hex[(num >> ((3 - i) * 4)) & 0xf];
0130 *c++ = '~';
0131 *c = '1';
0132 }
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144 #define MSDOS_NAME_TYPE_PRINT 0
0145 static msdos_name_type_t
0146 msdos_name_type(const char *name, int name_len)
0147 {
0148 bool lowercase = false;
0149 bool uppercase = false;
0150 int dot_at = -1;
0151 int count = 0;
0152
0153 while (*name && (count < name_len))
0154 {
0155 bool is_dot = *name == '.';
0156 msdos_name_type_t type = msdos_is_valid_name_char(*name);
0157
0158 #if MSDOS_NAME_TYPE_PRINT
0159 printf ("MSDOS_NAME_TYPE: c:%02x type:%d\n", *name, type);
0160 #endif
0161
0162 if ((type == MSDOS_NAME_INVALID) || (type == MSDOS_NAME_LONG))
0163 return type;
0164
0165 if (dot_at >= 0)
0166 {
0167 if (is_dot || ((count - dot_at) > 3))
0168 {
0169 #if MSDOS_NAME_TYPE_PRINT
0170 printf ("MSDOS_NAME_TYPE: LONG[1]: is_dot:%d, at:%d cnt\n",
0171 is_dot, dot_at, count);
0172 #endif
0173 return MSDOS_NAME_LONG;
0174 }
0175 }
0176 else
0177 {
0178 if (count == 8 && !is_dot)
0179 {
0180 #if MSDOS_NAME_TYPE_PRINT
0181 printf ("MSDOS_NAME_TYPE: LONG[2]: is_dot:%d, at:%d cnt\n",
0182 is_dot, dot_at, count);
0183 #endif
0184 return MSDOS_NAME_LONG;
0185 }
0186 }
0187
0188 if (is_dot)
0189 dot_at = count;
0190 else if ((*name >= 'A') && (*name <= 'Z'))
0191 uppercase = true;
0192 else if ((*name >= 'a') && (*name <= 'z'))
0193 lowercase = true;
0194
0195 count++;
0196 name++;
0197 }
0198
0199 if (lowercase && uppercase)
0200 {
0201 #if MSDOS_NAME_TYPE_PRINT
0202 printf ("MSDOS_NAME_TYPE: LONG[3]\n");
0203 #endif
0204 return MSDOS_NAME_LONG;
0205 }
0206
0207 #if MSDOS_NAME_TYPE_PRINT
0208 printf ("MSDOS_NAME_TYPE: SHORT[1]\n");
0209 #endif
0210 return MSDOS_NAME_SHORT;
0211 }
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223 #define MSDOS_L2S_PRINT 0
0224 msdos_name_type_t
0225 msdos_long_to_short(rtems_dosfs_convert_control *converter,
0226 const char *lfn,
0227 int lfn_len,
0228 char *sfn,
0229 int sfn_len)
0230 {
0231 msdos_name_type_t type;
0232 int eno = 0;
0233 int i;
0234 ssize_t short_filename_length = sfn_len;
0235 void *buffer = converter->buffer.data;
0236 size_t codepage_name_len = converter->buffer.size;
0237
0238
0239
0240
0241 memset (sfn, ' ', sfn_len);
0242
0243
0244
0245
0246 if ((lfn[0] == '.') && (lfn_len == 1))
0247 {
0248 sfn[0] = '.';
0249 #if MSDOS_L2S_PRINT
0250 printf ("MSDOS_L2S: SHORT[1]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
0251 #endif
0252 return MSDOS_NAME_SHORT;
0253 }
0254
0255 if ((lfn[0] == '.') && (lfn[1] == '.') && (lfn_len == 2))
0256 {
0257 sfn[0] = sfn[1] = '.';
0258 #if MSDOS_L2S_PRINT
0259 printf ("MSDOS_L2S: SHORT[2]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
0260 #endif
0261 return MSDOS_NAME_SHORT;
0262 }
0263
0264
0265
0266
0267 for (i = 0; i < lfn_len; i++)
0268 if ((lfn[i] != ' ') && (lfn[i] != '.'))
0269 break;
0270
0271 if (i == lfn_len)
0272 {
0273 #if MSDOS_L2S_PRINT
0274 printf ("MSDOS_L2S: INVALID[1]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
0275 #endif
0276 return MSDOS_NAME_INVALID;
0277 }
0278
0279
0280
0281
0282
0283 eno = (*converter->handler->utf8_to_codepage) (
0284 converter,
0285 (const uint8_t*)&lfn[0],
0286 lfn_len,
0287 buffer,
0288 &codepage_name_len);
0289 if (eno == EINVAL)
0290 {
0291 type = MSDOS_NAME_LONG;
0292 }
0293 else
0294 {
0295 type = msdos_name_type (
0296 buffer,
0297 codepage_name_len);
0298 }
0299
0300 if (type != MSDOS_NAME_INVALID)
0301 {
0302 short_filename_length = msdos_filename_utf8_to_short_name_for_save (
0303 converter,
0304 (const uint8_t*)lfn,
0305 lfn_len,
0306 sfn,
0307 short_filename_length);
0308 if (short_filename_length < 0 ) {
0309 type = MSDOS_NAME_INVALID;
0310 }
0311 #if MSDOS_L2S_PRINT
0312 printf ("MSDOS_L2S: TYPE:%d lfn:'%s' SFN:'%s'\n", type, lfn, sfn);
0313 #endif
0314 }
0315 else
0316 {
0317 #if MSDOS_L2S_PRINT
0318 printf ("MSDOS_L2S: INVALID[2]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
0319 #endif
0320 }
0321
0322 return type;
0323 }
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339 int
0340 msdos_find_name(
0341 rtems_filesystem_location_info_t *parent_loc,
0342 const char *name,
0343 int name_len
0344 )
0345 {
0346 int rc = RC_OK;
0347 msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
0348 fat_file_fd_t *fat_fd = NULL;
0349 msdos_name_type_t name_type;
0350 fat_dir_pos_t dir_pos;
0351 unsigned short time_val = 0;
0352 unsigned short date = 0;
0353 char node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
0354
0355 memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
0356
0357 name_type = msdos_long_to_short (
0358 fs_info->converter,
0359 name,
0360 name_len,
0361 MSDOS_DIR_NAME(node_entry),
0362 MSDOS_NAME_MAX);
0363
0364
0365
0366
0367
0368 rc = msdos_get_name_node(parent_loc, false, name, name_len, name_type,
0369 &dir_pos, node_entry);
0370 if (rc != RC_OK)
0371 return rc;
0372
0373 if (((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_VOLUME_ID) ||
0374 ((*MSDOS_DIR_ATTR(node_entry) & MSDOS_ATTR_LFN_MASK) == MSDOS_ATTR_LFN))
0375 return MSDOS_NAME_NOT_FOUND_ERR;
0376
0377
0378 rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
0379 if (rc != RC_OK)
0380 return rc;
0381
0382 fat_fd->dir_pos = dir_pos;
0383
0384
0385
0386
0387
0388
0389
0390
0391 if (fat_fd->links_num == 1)
0392 {
0393 fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
0394
0395 time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
0396 date = *MSDOS_DIR_WRITE_DATE(node_entry);
0397
0398 fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(date), CF_LE_W(time_val));
0399
0400 time_val = *MSDOS_DIR_CRT_TIME(node_entry);
0401 date = *MSDOS_DIR_CRT_DATE(node_entry);
0402
0403 fat_fd->ctime = msdos_date_dos2unix(CF_LE_W(date), CF_LE_W(time_val));
0404
0405 if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
0406 {
0407 fat_fd->fat_file_type = FAT_DIRECTORY;
0408 fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
0409
0410 rc = fat_file_size(&fs_info->fat, fat_fd);
0411 if (rc != RC_OK)
0412 {
0413 fat_file_close(&fs_info->fat, fat_fd);
0414 return rc;
0415 }
0416 }
0417 else
0418 {
0419 fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
0420 fat_fd->fat_file_type = FAT_FILE;
0421 fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
0422 }
0423
0424
0425 fat_fd->map.file_cln = 0;
0426 fat_fd->map.disk_cln = fat_fd->cln;
0427
0428 if ((fat_fd->fat_file_size != 0) &&
0429 (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
0430 {
0431 fat_fd->map.last_cln = fat_fd->cln;
0432 }
0433 else
0434 {
0435 fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
0436 }
0437 }
0438
0439
0440 rc = fat_file_close(&fs_info->fat, parent_loc->node_access);
0441 if (rc != RC_OK)
0442 {
0443 fat_file_close(&fs_info->fat, fat_fd);
0444 return rc;
0445 }
0446
0447
0448 parent_loc->node_access = fat_fd;
0449
0450 return rc;
0451 }
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481 int
0482 msdos_get_name_node(
0483 const rtems_filesystem_location_info_t *parent_loc,
0484 bool create_node,
0485 const char *name,
0486 int name_len,
0487 msdos_name_type_t name_type,
0488 fat_dir_pos_t *dir_pos,
0489 char *name_dir_entry
0490 )
0491 {
0492 int rc = RC_OK;
0493 fat_file_fd_t *fat_fd = parent_loc->node_access;
0494 uint32_t dotdot_cln = 0;
0495
0496
0497 rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd,
0498 create_node, (const uint8_t*)name, name_len, name_type,
0499 dir_pos, name_dir_entry);
0500 if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
0501 return rc;
0502
0503 if (!create_node)
0504 {
0505
0506 if (rc == MSDOS_NAME_NOT_FOUND_ERR)
0507 return rc;
0508
0509
0510
0511
0512
0513
0514
0515 if (rc == RC_OK)
0516 {
0517 if (strncmp(name, "..", 2) == 0)
0518 {
0519 dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry));
0520
0521
0522 if (dotdot_cln == 0)
0523 {
0524
0525
0526
0527
0528 fat_dir_pos_init(dir_pos);
0529 dir_pos->sname.cln = FAT_ROOTDIR_CLUSTER_NUM;
0530 }
0531 else
0532 {
0533 rc =
0534 msdos_get_dotdot_dir_info_cluster_num_and_offset(parent_loc->mt_entry,
0535 dotdot_cln,
0536 dir_pos,
0537 name_dir_entry);
0538 if (rc != RC_OK)
0539 return rc;
0540 }
0541 }
0542 }
0543 }
0544 return rc;
0545 }
0546
0547
0548
0549
0550
0551
0552
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 int
0577 msdos_get_dotdot_dir_info_cluster_num_and_offset(
0578 rtems_filesystem_mount_table_entry_t *mt_entry,
0579 uint32_t cln,
0580 fat_dir_pos_t *dir_pos,
0581 char *dir_entry
0582 )
0583 {
0584 int rc = RC_OK;
0585 msdos_fs_info_t *fs_info = mt_entry->fs_info;
0586 fat_file_fd_t *fat_fd = NULL;
0587 char dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
0588 char dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
0589 uint32_t cl4find = 0;
0590 rtems_dosfs_convert_control *converter = fs_info->converter;
0591
0592
0593
0594
0595 rc = fat_file_open(&fs_info->fat, dir_pos, &fat_fd);
0596 if (rc != RC_OK)
0597 return rc;
0598
0599 fat_fd->cln = cln;
0600 fat_fd->fat_file_type = FAT_DIRECTORY;
0601 fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
0602
0603 fat_fd->map.file_cln = 0;
0604 fat_fd->map.disk_cln = fat_fd->cln;
0605
0606 rc = fat_file_size(&fs_info->fat, fat_fd);
0607 if (rc != RC_OK)
0608 {
0609 fat_file_close(&fs_info->fat, fat_fd);
0610 return rc;
0611 }
0612
0613
0614 memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
0615 msdos_long_to_short(
0616 converter,
0617 ".", 1, dot_node, MSDOS_SHORT_NAME_LEN);
0618 rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)".", 1,
0619 MSDOS_NAME_SHORT, dir_pos, dot_node);
0620
0621 if (rc != RC_OK)
0622 {
0623 fat_file_close(&fs_info->fat, fat_fd);
0624 return rc;
0625 }
0626
0627
0628 memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
0629 msdos_long_to_short(
0630 converter,
0631 "..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN);
0632 rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)"..", 2,
0633 MSDOS_NAME_SHORT, dir_pos,
0634 dotdot_node);
0635
0636 if (rc != RC_OK)
0637 {
0638 fat_file_close(&fs_info->fat, fat_fd);
0639 return rc;
0640 }
0641
0642 cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
0643
0644
0645 rc = fat_file_close(&fs_info->fat, fat_fd);
0646 if ( rc != RC_OK )
0647 return rc;
0648
0649 if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
0650 {
0651
0652
0653
0654
0655 fat_dir_pos_init(dir_pos);
0656 dir_pos->sname.cln = FAT_ROOTDIR_CLUSTER_NUM;
0657 }
0658
0659
0660 rc = fat_file_open(&fs_info->fat, dir_pos, &fat_fd);
0661 if (rc != RC_OK)
0662 return rc;
0663
0664 if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
0665 fat_fd->cln = fs_info->fat.vol.rdir_cl;
0666 else
0667 fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
0668
0669 fat_fd->fat_file_type = FAT_DIRECTORY;
0670 fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
0671
0672 fat_fd->map.file_cln = 0;
0673 fat_fd->map.disk_cln = fat_fd->cln;
0674
0675 rc = fat_file_size(&fs_info->fat, fat_fd);
0676 if (rc != RC_OK)
0677 {
0678 fat_file_close(&fs_info->fat, fat_fd);
0679 return rc;
0680 }
0681
0682
0683 rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
0684 dir_pos, dir_entry);
0685 if (rc != RC_OK)
0686 {
0687 fat_file_close(&fs_info->fat, fat_fd);
0688 return rc;
0689 }
0690 rc = fat_file_close(&fs_info->fat, fat_fd);
0691 return rc;
0692 }
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707 int
0708 fat_file_write_time_and_date(
0709 fat_fs_info_t *fs_info,
0710 fat_file_fd_t *fat_fd
0711 )
0712 {
0713 int rc = RC_OK;
0714 ssize_t ret;
0715 uint16_t time_val;
0716 uint16_t date;
0717 uint32_t sec = 0;
0718 uint32_t byte = 0;
0719
0720
0721
0722
0723
0724 sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->dir_pos.sname.cln);
0725 sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
0726
0727 byte = fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1);
0728
0729 msdos_date_unix2dos(fat_fd->mtime, &date, &time_val);
0730
0731 time_val = CT_LE_W(time_val);
0732 ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_WTIME_OFFSET,
0733 2, (char *)(&time_val));
0734 if ( ret < 0 )
0735 rc = -1;
0736
0737 date = CT_LE_W(date);
0738 ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_WDATE_OFFSET,
0739 2, (char *)(&date));
0740 if ( ret < 0 )
0741 rc = -1;
0742
0743 ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_ADATE_OFFSET,
0744 2, (char *)(&date));
0745 if ( ret < 0 )
0746 rc = -1;
0747
0748 msdos_date_unix2dos(fat_fd->ctime, &date, &time_val);
0749
0750 time_val = CT_LE_W(time_val);
0751 ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_CTIME_OFFSET,
0752 2, (char *)(&time_val));
0753 if ( ret < 0 )
0754 rc = -1;
0755
0756 date = CT_LE_W(date);
0757 ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_CDATE_OFFSET,
0758 2, (char *)(&date));
0759 if ( ret < 0 )
0760 rc = -1;
0761
0762 return rc;
0763 }
0764
0765
0766
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777 int
0778 fat_file_write_first_cluster_num(
0779 fat_fs_info_t *fs_info,
0780 fat_file_fd_t *fat_fd
0781 )
0782 {
0783 ssize_t ret1 = 0, ret2 = 0;
0784 uint32_t new_cln = fat_fd->cln;
0785 uint16_t le_cl_low = 0;
0786 uint16_t le_cl_hi = 0;
0787 uint32_t sec = 0;
0788 uint32_t byte = 0;
0789
0790
0791
0792
0793
0794 sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->dir_pos.sname.cln);
0795 sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
0796
0797 byte = fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1);
0798
0799 le_cl_low = CT_LE_W((uint16_t )(new_cln & 0x0000FFFF));
0800 ret1 = fat_sector_write(fs_info, sec,
0801 byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
0802 (char *)(&le_cl_low));
0803 le_cl_hi = CT_LE_W((uint16_t )((new_cln & 0xFFFF0000) >> 16));
0804 ret2 = fat_sector_write(fs_info, sec,
0805 byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
0806 (char *)(&le_cl_hi));
0807 if ( (ret1 < 0) || (ret2 < 0) )
0808 return -1;
0809
0810 return RC_OK;
0811 }
0812
0813
0814
0815
0816
0817
0818
0819
0820
0821
0822
0823
0824
0825 int
0826 fat_file_write_file_size(
0827 fat_fs_info_t *fs_info,
0828 fat_file_fd_t *fat_fd
0829 )
0830 {
0831 ssize_t ret = 0;
0832 uint32_t le_new_length = 0;
0833 uint32_t sec = 0;
0834 uint32_t byte = 0;
0835
0836 sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->dir_pos.sname.cln);
0837 sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
0838 byte = (fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1));
0839
0840 if (fat_fd->fat_file_type == FAT_DIRECTORY) {
0841 le_new_length = CT_LE_L(0);
0842 } else {
0843 le_new_length = CT_LE_L(fat_fd->fat_file_size);
0844 }
0845
0846 ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
0847 (char *)(&le_new_length));
0848 if ( ret < 0 )
0849 return -1;
0850
0851 return RC_OK;
0852 }
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872
0873 int
0874 msdos_set_first_char4file_name(
0875 rtems_filesystem_mount_table_entry_t *mt_entry,
0876 fat_dir_pos_t *dir_pos,
0877 unsigned char fchar
0878 )
0879 {
0880 ssize_t ret;
0881 msdos_fs_info_t *fs_info = mt_entry->fs_info;
0882 uint32_t dir_block_size;
0883 fat_pos_t start = dir_pos->lname;
0884 fat_pos_t end = dir_pos->sname;
0885
0886 if ((end.cln == fs_info->fat.vol.rdir_cl) &&
0887 (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
0888 dir_block_size = fs_info->fat.vol.rdir_size;
0889 else
0890 dir_block_size = fs_info->fat.vol.bpc;
0891
0892 if (dir_pos->lname.cln == FAT_FILE_SHORT_NAME)
0893 start = dir_pos->sname;
0894
0895
0896
0897
0898
0899
0900 while (true)
0901 {
0902 uint32_t sec = (fat_cluster_num_to_sector_num(&fs_info->fat, start.cln) +
0903 (start.ofs >> fs_info->fat.vol.sec_log2));
0904 uint32_t byte = (start.ofs & (fs_info->fat.vol.bps - 1));
0905
0906 ret = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_NAME_OFFSET,
0907 1, &fchar);
0908 if (ret < 0)
0909 return -1;
0910
0911 if ((start.cln == end.cln) && (start.ofs == end.ofs))
0912 break;
0913
0914 start.ofs += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
0915 if (start.ofs >= dir_block_size)
0916 {
0917 int rc;
0918 if ((end.cln == fs_info->fat.vol.rdir_cl) &&
0919 (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
0920 break;
0921 rc = fat_get_fat_cluster(&fs_info->fat, start.cln, &start.cln);
0922 if ( rc != RC_OK )
0923 return rc;
0924 start.ofs = 0;
0925 }
0926 }
0927
0928 return RC_OK;
0929 }
0930
0931
0932
0933
0934
0935
0936
0937
0938
0939
0940
0941
0942
0943
0944 int
0945 msdos_dir_is_empty(
0946 rtems_filesystem_mount_table_entry_t *mt_entry,
0947 fat_file_fd_t *fat_fd,
0948 bool *ret_val
0949 )
0950 {
0951 ssize_t ret = 0;
0952 msdos_fs_info_t *fs_info = mt_entry->fs_info;
0953 uint32_t j = 0, i = 0;
0954
0955
0956 *ret_val = false;
0957
0958 while ((ret = fat_file_read(&fs_info->fat, fat_fd, j * fs_info->fat.vol.bps,
0959 fs_info->fat.vol.bps,
0960 fs_info->cl_buf)) != FAT_EOF)
0961 {
0962 if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
0963 return -1;
0964
0965 assert(ret == fs_info->fat.vol.bps);
0966
0967
0968 for (i = 0;
0969 i < fs_info->fat.vol.bps;
0970 i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
0971 {
0972 char* entry = (char*) fs_info->cl_buf + i;
0973
0974
0975
0976
0977
0978
0979
0980
0981 if (((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
0982 MSDOS_THIS_DIR_ENTRY_EMPTY) ||
0983 ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
0984 MSDOS_ATTR_LFN) ||
0985 (strncmp(MSDOS_DIR_NAME((entry)), MSDOS_DOT_NAME,
0986 MSDOS_SHORT_NAME_LEN) == 0) ||
0987 (strncmp(MSDOS_DIR_NAME((entry)),
0988 MSDOS_DOTDOT_NAME,
0989 MSDOS_SHORT_NAME_LEN) == 0))
0990 continue;
0991
0992
0993
0994
0995 if ((*MSDOS_DIR_NAME(entry)) ==
0996 MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
0997 {
0998 *ret_val = true;
0999 return RC_OK;
1000 }
1001
1002
1003
1004
1005 return RC_OK;
1006 }
1007 j++;
1008 }
1009 *ret_val = true;
1010 return RC_OK;
1011 }
1012
1013 #define MSDOS_FIND_PRINT 0
1014 static int
1015 msdos_on_entry_found (
1016 msdos_fs_info_t *fs_info,
1017 fat_file_fd_t *fat_fd,
1018 const uint32_t bts2rd,
1019 char *name_dir_entry,
1020 char *entry,
1021 fat_dir_pos_t *dir_pos,
1022 uint32_t dir_offset,
1023 const uint32_t dir_entry,
1024 const fat_pos_t *lfn_start
1025 )
1026 {
1027 int rc = RC_OK;
1028 #if MSDOS_FIND_PRINT
1029 printf ("MSFS:[9.3] SNF found\n");
1030 #endif
1031
1032
1033
1034
1035 rc = fat_file_ioctl(&fs_info->fat,
1036 fat_fd,
1037 F_CLU_NUM,
1038 dir_offset * bts2rd,
1039 &dir_pos->sname.cln);
1040 if (rc == RC_OK) {
1041 dir_pos->sname.ofs = dir_entry;
1042
1043 if (lfn_start->cln != FAT_FILE_SHORT_NAME)
1044 {
1045 rc = fat_file_ioctl (&fs_info->fat,
1046 fat_fd,
1047 F_CLU_NUM,
1048 lfn_start->cln * bts2rd,
1049 &lfn_start->cln);
1050 }
1051 if ( rc == RC_OK ) {
1052 dir_pos->lname.cln = lfn_start->cln;
1053 dir_pos->lname.ofs = lfn_start->ofs;
1054
1055 memcpy(name_dir_entry, entry,
1056 MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1057 }
1058 }
1059
1060 return rc;
1061 }
1062
1063 ssize_t
1064 msdos_get_utf16_string_from_long_entry (
1065 const char *entry,
1066 uint16_t *entry_string_buf,
1067 const size_t buf_size,
1068 bool is_first_entry
1069 )
1070 {
1071 ssize_t chars_in_entry;
1072
1073 if (buf_size >= MSDOS_LFN_ENTRY_SIZE) {
1074 memcpy (&entry_string_buf[0], &entry[1], 10 );
1075 memcpy (&entry_string_buf[5], &entry[14], 12 );
1076 memcpy (&entry_string_buf[11], &entry[28], 4 );
1077
1078 if (is_first_entry) {
1079 for (chars_in_entry = 0;
1080 ( chars_in_entry < MSDOS_LFN_LEN_PER_ENTRY
1081 && entry_string_buf[chars_in_entry] != 0x0000);
1082 ++chars_in_entry) {
1083 ;
1084 }
1085 }
1086 else
1087 chars_in_entry = MSDOS_LFN_LEN_PER_ENTRY;
1088
1089 return chars_in_entry * MSDOS_NAME_LFN_BYTES_PER_CHAR;
1090 }
1091 else
1092 return ENOMEM;
1093 }
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114 ssize_t
1115 msdos_format_dirent_with_dot(char *dst,const char *src)
1116 {
1117 ssize_t len;
1118 int i;
1119 const char *src_tmp;
1120
1121
1122
1123
1124 for (i = MSDOS_SHORT_BASE_LEN, src_tmp = src + MSDOS_SHORT_BASE_LEN - 1;
1125 i > 0 && *src_tmp == ' ';
1126 --i,--src_tmp)
1127 {};
1128
1129
1130
1131 src_tmp = src;
1132 len = i;
1133 while (i-- > 0) {
1134 *dst++ = tolower((unsigned char)(*src_tmp++));
1135 }
1136
1137
1138
1139 for (i = MSDOS_SHORT_EXT_LEN,
1140 src_tmp = src + MSDOS_SHORT_BASE_LEN+MSDOS_SHORT_EXT_LEN-1;
1141 i > 0 && *src_tmp == ' ';
1142 --i, --src_tmp)
1143 {};
1144
1145
1146
1147 if (i > 0) {
1148 *dst++ = '.';
1149 ++len;
1150 src_tmp = src + MSDOS_SHORT_BASE_LEN;
1151 while (i-- > 0) {
1152 *dst++ = tolower((unsigned char)(*src_tmp++));
1153 ++len;
1154 }
1155 }
1156 *dst = '\0';
1157
1158 return len;
1159 }
1160
1161 static ssize_t
1162 msdos_long_entry_to_utf8_name (
1163 rtems_dosfs_convert_control *converter,
1164 const char *entry,
1165 const bool is_first_entry,
1166 uint8_t *entry_utf8_buf,
1167 const size_t buf_size)
1168 {
1169 ssize_t retval = 0;
1170 int eno = 0;
1171 size_t bytes_in_utf8 = buf_size;
1172 size_t bytes_in_buf;
1173 uint16_t entry_string[MSDOS_LFN_LEN_PER_ENTRY];
1174
1175 retval = msdos_get_utf16_string_from_long_entry (
1176 entry,
1177 entry_string,
1178 sizeof (entry_string),
1179 is_first_entry
1180 );
1181
1182 if (retval >= 0) {
1183 bytes_in_buf = retval;
1184 eno = (*converter->handler->utf16_to_utf8) (
1185 converter,
1186 &entry_string[0],
1187 bytes_in_buf,
1188 &entry_utf8_buf[0],
1189 &bytes_in_utf8);
1190 if ( eno == 0 ) {
1191 retval = bytes_in_utf8;
1192 }
1193 }
1194
1195 if (eno != 0) {
1196 retval = -1;
1197 errno = eno;
1198 }
1199
1200 return retval;
1201 }
1202
1203 static ssize_t msdos_short_entry_to_utf8_name (
1204 rtems_dosfs_convert_control *converter,
1205 const char *entry,
1206 uint8_t *buf,
1207 const size_t buf_size)
1208 {
1209 char char_buf[MSDOS_NAME_MAX_WITH_DOT];
1210 int eno = 0;
1211 size_t bytes_converted = buf_size;
1212 ssize_t bytes_written = msdos_format_dirent_with_dot(char_buf, entry);
1213
1214 if (bytes_written > 0) {
1215 if (char_buf[0] == 0x05)
1216 char_buf[0] = 0xE5;
1217
1218 eno = (*converter->handler->codepage_to_utf8) (
1219 converter,
1220 char_buf,
1221 bytes_written,
1222 buf,
1223 &bytes_converted);
1224 if (eno == 0)
1225 bytes_written = bytes_converted;
1226 } else {
1227 eno = EINVAL;
1228 }
1229
1230 if (eno != 0) {
1231 bytes_written = -1;
1232 errno = eno;
1233 }
1234
1235 return bytes_written;
1236 }
1237
1238 static ssize_t
1239 msdos_compare_entry_against_filename (
1240 rtems_dosfs_convert_control *converter,
1241 const uint8_t *entry,
1242 const size_t entry_size,
1243 const uint8_t *filename,
1244 const size_t name_len_remaining,
1245 bool *is_matching)
1246 {
1247 ssize_t size_remaining = name_len_remaining;
1248 int eno = 0;
1249 uint8_t entry_normalized[MSDOS_LFN_ENTRY_SIZE_UTF8];
1250 size_t bytes_in_entry_normalized = sizeof ( entry_normalized );
1251
1252 eno = (*converter->handler->utf8_normalize_and_fold) (
1253 converter,
1254 &entry[0],
1255 entry_size,
1256 &entry_normalized[0],
1257 &bytes_in_entry_normalized);
1258 if (eno == 0) {
1259 #if MSDOS_FIND_PRINT > 1
1260 printf ( "MSFS:[6] entry_normalized:%s"
1261 "name:%s\n",
1262 entry,
1263 filename );
1264 #endif
1265 if (bytes_in_entry_normalized <= size_remaining) {
1266 size_remaining = size_remaining - bytes_in_entry_normalized;
1267 if (0 == memcmp ( &entry_normalized[0],
1268 &filename[size_remaining],
1269 bytes_in_entry_normalized)) {
1270 *is_matching = true;
1271 } else {
1272 *is_matching = false;
1273 size_remaining = name_len_remaining;
1274 }
1275
1276 }
1277 else {
1278 *is_matching = false;
1279 }
1280 }
1281
1282 if (eno != 0) {
1283 size_remaining = -1;
1284 errno = eno;
1285 }
1286
1287 return size_remaining;
1288 }
1289
1290 static void
1291 msdos_prepare_for_next_entry(
1292 fat_pos_t *lfn_start,
1293 bool *entry_matched,
1294 ssize_t *name_len_remaining,
1295 size_t name_len_for_compare)
1296 {
1297 lfn_start->cln = FAT_FILE_SHORT_NAME;
1298 *entry_matched = false;
1299 *name_len_remaining = name_len_for_compare;
1300 }
1301
1302 static int
1303 msdos_find_file_in_directory (
1304 const uint8_t *filename_converted,
1305 const size_t name_len_for_compare,
1306 const msdos_name_type_t name_type,
1307 msdos_fs_info_t *fs_info,
1308 fat_file_fd_t *fat_fd,
1309 const uint32_t bts2rd,
1310 const bool create_node,
1311 const unsigned int lfn_entries,
1312 char *name_dir_entry,
1313 fat_dir_pos_t *dir_pos,
1314 uint32_t *empty_file_offset,
1315 uint32_t *empty_entry_count)
1316 {
1317 int rc = RC_OK;
1318 ssize_t bytes_read;
1319 uint32_t dir_entry;
1320 fat_pos_t lfn_start;
1321 uint8_t lfn_checksum = 0;
1322 bool entry_matched;
1323 bool empty_space_found = false;
1324 uint32_t entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1325 int lfn_entry = 0;
1326 uint8_t entry_utf8_normalized[MSDOS_LFN_ENTRY_SIZE_UTF8];
1327 size_t bytes_in_entry;
1328 bool filename_matched = false;
1329 ssize_t name_len_remaining;
1330 rtems_dosfs_convert_control *converter = fs_info->converter;
1331 uint32_t dir_offset = 0;
1332
1333
1334
1335
1336
1337
1338
1339 msdos_prepare_for_next_entry(&lfn_start, &entry_matched,
1340 &name_len_remaining,
1341 name_len_for_compare);
1342
1343 while ( (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (dir_offset * bts2rd),
1344 bts2rd, fs_info->cl_buf)) != FAT_EOF
1345 && rc == RC_OK)
1346 {
1347 bool remainder_empty = false;
1348 #if MSDOS_FIND_PRINT
1349 printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
1350 #endif
1351
1352 if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
1353 rtems_set_errno_and_return_minus_one(EIO);
1354
1355 assert(bytes_read == bts2rd);
1356
1357
1358 for (dir_entry = 0;
1359 dir_entry < bts2rd && rc == RC_OK && (! filename_matched);
1360 dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
1361 {
1362 char* entry = (char*) fs_info->cl_buf + dir_entry;
1363
1364
1365
1366
1367
1368 bool entry_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
1369 MSDOS_THIS_DIR_ENTRY_EMPTY);
1370 remainder_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
1371 MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
1372 #if MSDOS_FIND_PRINT
1373 printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
1374 remainder_empty, entry_empty, dir_offset,
1375 dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
1376 #endif
1377
1378
1379
1380
1381
1382
1383
1384 if (*empty_entry_count == 0)
1385 {
1386 *empty_file_offset = dir_offset * bts2rd + dir_entry;
1387 }
1388
1389 if (remainder_empty)
1390 {
1391 #if MSDOS_FIND_PRINT
1392 printf ("MSFS:[3.1] cn:%i esf:%i\n", create_node, empty_space_found);
1393 #endif
1394
1395
1396
1397
1398 if (!create_node)
1399 rc = MSDOS_NAME_NOT_FOUND_ERR;
1400
1401
1402
1403
1404
1405
1406
1407 if ( !empty_space_found
1408 && rc == RC_OK )
1409 {
1410 *empty_entry_count +=
1411 entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1412 empty_space_found = true;
1413 #if MSDOS_FIND_PRINT
1414 printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_entry_count );
1415 #endif
1416 }
1417 break;
1418 }
1419 else if (entry_empty)
1420 {
1421 if (create_node)
1422 {
1423
1424
1425
1426 (*empty_entry_count)++;
1427
1428 if (*empty_entry_count == (lfn_entries + 1))
1429 empty_space_found = true;
1430 }
1431 #if MSDOS_FIND_PRINT
1432 printf ("MSFS:[4.1] esc:%li esf:%i\n",
1433 *empty_entry_count, empty_space_found);
1434 #endif
1435 msdos_prepare_for_next_entry(&lfn_start, &entry_matched,
1436 &name_len_remaining,
1437 name_len_for_compare);
1438 }
1439 else
1440 {
1441
1442
1443
1444
1445
1446
1447 if (create_node && !empty_space_found)
1448 {
1449 *empty_file_offset = 0;
1450 *empty_entry_count = 0;
1451 }
1452
1453
1454
1455
1456
1457 if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
1458 MSDOS_ATTR_LFN)
1459 {
1460 bool is_first_lfn_entry =
1461 (lfn_start.cln == FAT_FILE_SHORT_NAME);
1462
1463
1464 #if MSDOS_FIND_PRINT
1465 printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
1466 lfn_start.cln == FAT_FILE_SHORT_NAME ? 'f' : 't',
1467 *MSDOS_DIR_ENTRY_TYPE(entry) & MSDOS_LAST_LONG_ENTRY_MASK,
1468 *MSDOS_DIR_LFN_CHECKSUM(entry));
1469 #endif
1470
1471
1472
1473
1474 if (is_first_lfn_entry)
1475 {
1476 entry_matched = false;
1477
1478
1479
1480
1481
1482 if ((*MSDOS_DIR_ENTRY_TYPE(entry) &
1483 MSDOS_LAST_LONG_ENTRY) == 0)
1484 continue;
1485
1486 lfn_start.cln = dir_offset;
1487 lfn_start.ofs = dir_entry;
1488 lfn_entry = (*MSDOS_DIR_ENTRY_TYPE(entry)
1489 & MSDOS_LAST_LONG_ENTRY_MASK);
1490 lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
1491
1492 #if MSDOS_FIND_PRINT
1493 printf ("MSFS:[4.3] lfn_checksum:%i\n",
1494 lfn_checksum);
1495 #endif
1496 }
1497
1498
1499
1500
1501
1502
1503
1504 if ((lfn_entry != (*MSDOS_DIR_ENTRY_TYPE(entry) &
1505 MSDOS_LAST_LONG_ENTRY_MASK)) ||
1506 (lfn_checksum != *MSDOS_DIR_LFN_CHECKSUM(entry)))
1507 {
1508 #if MSDOS_FIND_PRINT
1509 printf ("MSFS:[4.4] no match\n");
1510 #endif
1511 msdos_prepare_for_next_entry(&lfn_start,
1512 &entry_matched,
1513 &name_len_remaining,
1514 name_len_for_compare);
1515 continue;
1516 }
1517 #if MSDOS_FIND_PRINT
1518 printf ("MSFS:[5] lfne:%i\n", lfn_entry);
1519 #endif
1520 lfn_entry--;
1521
1522 bytes_in_entry = msdos_long_entry_to_utf8_name (
1523 converter,
1524 entry,
1525 is_first_lfn_entry,
1526 &entry_utf8_normalized[0],
1527 sizeof (entry_utf8_normalized));
1528 if (bytes_in_entry > 0) {
1529 name_len_remaining = msdos_compare_entry_against_filename (
1530 converter,
1531 &entry_utf8_normalized[0],
1532 bytes_in_entry,
1533 &filename_converted[0],
1534 name_len_remaining,
1535 &entry_matched);
1536
1537 if (name_len_remaining < 0 || !entry_matched) {
1538 msdos_prepare_for_next_entry(&lfn_start,
1539 &entry_matched,
1540 &name_len_remaining,
1541 name_len_for_compare);
1542 }
1543 } else {
1544 msdos_prepare_for_next_entry(&lfn_start,
1545 &entry_matched,
1546 &name_len_remaining,
1547 name_len_for_compare);
1548 }
1549 }
1550 else
1551 {
1552 #if MSDOS_FIND_PRINT
1553 printf ("MSFS:[9.1] SFN entry, entry_matched:%i\n", entry_matched);
1554 #endif
1555
1556
1557
1558
1559
1560
1561
1562
1563 if (entry_matched)
1564 {
1565 if (lfn_entry ||
1566 name_len_remaining > 0 ||
1567 lfn_checksum != msdos_lfn_checksum(entry)) {
1568 msdos_prepare_for_next_entry(&lfn_start,
1569 &entry_matched,
1570 &name_len_remaining,
1571 name_len_for_compare);
1572 } else if (name_len_remaining == 0) {
1573 filename_matched = true;
1574 rc = msdos_on_entry_found (
1575 fs_info,
1576 fat_fd,
1577 bts2rd,
1578 name_dir_entry,
1579 entry,
1580 dir_pos,
1581 dir_offset,
1582 dir_entry,
1583 &lfn_start
1584 );
1585 }
1586
1587 #if MSDOS_FIND_PRINT
1588 printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
1589 entry_matched, lfn_entry, lfn_checksum, msdos_lfn_checksum(entry));
1590 #endif
1591 } else if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_VOLUME_ID)
1592 == 0) {
1593 bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
1594 bytes_in_entry = msdos_short_entry_to_utf8_name (
1595 converter,
1596 MSDOS_DIR_NAME (entry),
1597 &entry_utf8_normalized[0],
1598 bytes_in_entry);
1599 if (bytes_in_entry > 0) {
1600 name_len_remaining = msdos_compare_entry_against_filename (
1601 converter,
1602 &entry_utf8_normalized[0],
1603 bytes_in_entry,
1604 &filename_converted[0],
1605 name_len_for_compare,
1606 &entry_matched);
1607 if (entry_matched && name_len_remaining == 0) {
1608 filename_matched = true;
1609 rc = msdos_on_entry_found (
1610 fs_info,
1611 fat_fd,
1612 bts2rd,
1613 name_dir_entry,
1614 entry,
1615 dir_pos,
1616 dir_offset,
1617 dir_entry,
1618 &lfn_start
1619 );
1620 }
1621 if (rc == RC_OK && !filename_matched) {
1622 msdos_prepare_for_next_entry(&lfn_start,
1623 &entry_matched,
1624 &name_len_remaining,
1625 name_len_for_compare);
1626 }
1627 } else {
1628 msdos_prepare_for_next_entry(&lfn_start,
1629 &entry_matched,
1630 &name_len_remaining,
1631 name_len_for_compare);
1632 }
1633 }
1634 }
1635 }
1636 }
1637
1638 if (filename_matched || remainder_empty)
1639 break;
1640
1641 dir_offset++;
1642 }
1643 if ( ! filename_matched ) {
1644
1645
1646
1647 if (!create_node)
1648 rc = MSDOS_NAME_NOT_FOUND_ERR;
1649
1650 #if MSDOS_FIND_PRINT
1651 printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" efo:%"PRIu32"\n",
1652 dir_offset, *empty_entry_count, *empty_file_offset );
1653 #endif
1654 }
1655
1656 return rc;
1657 }
1658
1659 static int
1660 msdos_get_pos(
1661 msdos_fs_info_t *fs_info,
1662 fat_file_fd_t *fat_fd,
1663 uint32_t bts2rd,
1664 uint32_t file_offset,
1665 fat_pos_t *pos
1666 )
1667 {
1668 pos->ofs = file_offset & (bts2rd - 1);
1669 return fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
1670 file_offset, &pos->cln);
1671 }
1672
1673 static int
1674 msdos_add_file (
1675 const char *name_converted,
1676 const msdos_name_type_t name_type,
1677 msdos_fs_info_t *fs_info,
1678 fat_file_fd_t *fat_fd,
1679 const uint32_t bts2rd,
1680 const unsigned int lfn_entries,
1681 const char *name_dir_entry,
1682 fat_dir_pos_t *dir_pos,
1683 uint32_t empty_file_offset,
1684 const uint32_t empty_entry_count
1685 )
1686 {
1687 int ret;
1688 ssize_t bytes_written;
1689 uint8_t lfn_checksum;
1690 int lfn_entry;
1691 uint8_t *entry;
1692 uint32_t short_file_offset;
1693 uint32_t length;
1694
1695
1696
1697
1698 if (empty_entry_count < lfn_entries + 1)
1699 {
1700 uint32_t unused;
1701
1702 empty_file_offset = fat_fd->fat_file_size -
1703 empty_entry_count * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1704
1705 ret = fat_file_extend(&fs_info->fat,
1706 fat_fd,
1707 true,
1708 fat_fd->fat_file_size + fs_info->fat.vol.bpc,
1709 &unused);
1710 if (ret != RC_OK)
1711 return ret;
1712 }
1713
1714 if (name_type == MSDOS_NAME_LONG)
1715 {
1716 uint32_t slot;
1717
1718
1719
1720
1721
1722
1723
1724 slot = (empty_file_offset /
1725 MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1;
1726 msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
1727
1728 lfn_checksum = msdos_lfn_checksum(name_dir_entry);
1729
1730 short_file_offset = empty_file_offset + lfn_entries
1731 * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1732
1733
1734 ret = msdos_get_pos(fs_info, fat_fd, bts2rd, empty_file_offset,
1735 &dir_pos->lname);
1736 if (ret != RC_OK)
1737 return ret;
1738 } else {
1739 lfn_checksum = 0;
1740 short_file_offset = empty_file_offset;
1741 dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
1742 dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
1743 }
1744
1745
1746 ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
1747 &dir_pos->sname);
1748 if (ret != RC_OK)
1749 return ret;
1750
1751
1752
1753
1754 entry = fs_info->cl_buf;
1755
1756 #if MSDOS_FIND_PRINT
1757 printf ("MSFS:[9] read_cluster:%d efo:%ld ese:%ld\n",
1758 read_cluster, empty_file_offset, empty_space_entry);
1759 #endif
1760
1761
1762 for (lfn_entry = 0; lfn_entry < lfn_entries; ++lfn_entry) {
1763 uint8_t *p;
1764 const uint8_t *n;
1765 int i;
1766 uint8_t fill = 0;
1767
1768
1769
1770
1771 memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1772
1773 *MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
1774
1775 p = entry + 1;
1776 n = (const uint8_t *) name_converted +
1777 (lfn_entries - lfn_entry - 1) * MSDOS_LFN_ENTRY_SIZE;
1778
1779 #if MSDOS_FIND_PRINT
1780 printf ("MSFS:[11] ");
1781 #endif
1782 for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
1783 {
1784 if (*n != 0 || *(n + 1) != 0)
1785 {
1786 *p = *n;
1787 *(p + 1) = *(n + 1);
1788 n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
1789 }
1790 else
1791 {
1792 p [0] = fill;
1793 p [1] = fill;
1794 fill = 0xff;
1795 }
1796 #if MSDOS_FIND_PRINT
1797 printf ( "'%c''%c'", *p, *(p+1) );
1798 #endif
1799
1800 switch (i)
1801 {
1802 case 4:
1803 p += 5;
1804 break;
1805 case 10:
1806 p += 4;
1807 break;
1808 default:
1809 p += 2;
1810 break;
1811 }
1812 }
1813 #if MSDOS_FIND_PRINT
1814 printf ( "\n" );
1815 #endif
1816 *MSDOS_DIR_ENTRY_TYPE(entry) = lfn_entries - lfn_entry;
1817 if (lfn_entry == 0)
1818 *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
1819 *MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
1820
1821 entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1822 }
1823
1824
1825 memcpy(entry, name_dir_entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1826
1827 length = (lfn_entries + 1) * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1828 bytes_written = fat_file_write(&fs_info->fat, fat_fd,
1829 empty_file_offset,
1830 length, fs_info->cl_buf);
1831 if (bytes_written == (ssize_t) length)
1832 return 0;
1833 else if (bytes_written == -1)
1834 return -1;
1835 else
1836 rtems_set_errno_and_return_minus_one(EIO);
1837 }
1838
1839 int
1840 msdos_find_name_in_fat_file (
1841 rtems_filesystem_mount_table_entry_t *mt_entry,
1842 fat_file_fd_t *fat_fd,
1843 bool create_node,
1844 const uint8_t *name_utf8,
1845 int name_utf8_len,
1846 msdos_name_type_t name_type,
1847 fat_dir_pos_t *dir_pos,
1848 char *name_dir_entry)
1849 {
1850 int retval = 0;
1851 msdos_fs_info_t *fs_info = mt_entry->fs_info;
1852 ssize_t name_len_for_save;
1853 ssize_t name_len_for_compare;
1854 uint32_t bts2rd = 0;
1855 uint32_t empty_file_offset = 0;
1856 uint32_t empty_entry_count = 0;
1857 unsigned int lfn_entries;
1858 rtems_dosfs_convert_control *converter = fs_info->converter;
1859 void *buffer = converter->buffer.data;
1860 size_t buffer_size = converter->buffer.size;
1861
1862 assert(name_utf8_len > 0);
1863
1864 fat_dir_pos_init(dir_pos);
1865
1866
1867
1868 if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
1869 (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
1870 bts2rd = fat_fd->fat_file_size;
1871 else
1872 bts2rd = fs_info->fat.vol.bpc;
1873
1874 switch ( name_type ) {
1875 case MSDOS_NAME_SHORT:
1876 name_len_for_compare = msdos_filename_utf8_to_short_name_for_compare (
1877 converter,
1878 name_utf8,
1879 name_utf8_len,
1880 buffer,
1881 MSDOS_SHORT_NAME_LEN);
1882 if (name_len_for_compare > 0) {
1883 lfn_entries = 0;
1884 }
1885 else
1886 retval = -1;
1887 break;
1888 case MSDOS_NAME_LONG:
1889 name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
1890 converter,
1891 name_utf8,
1892 name_utf8_len,
1893 buffer,
1894 buffer_size);
1895 if (name_len_for_save > 0) {
1896 lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
1897 / MSDOS_LFN_ENTRY_SIZE;
1898 name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
1899 converter,
1900 name_utf8,
1901 name_utf8_len,
1902 buffer,
1903 buffer_size);
1904 if (0 >= name_len_for_compare) {
1905 retval = -1;
1906 }
1907 }
1908 else
1909 retval = -1;
1910 break;
1911 default:
1912 errno = EINVAL;
1913 retval = -1;
1914 break;
1915 }
1916 if (retval == RC_OK) {
1917
1918 retval = msdos_find_file_in_directory (
1919 buffer,
1920 name_len_for_compare,
1921 name_type,
1922 fs_info,
1923 fat_fd,
1924 bts2rd,
1925 create_node,
1926 lfn_entries,
1927 name_dir_entry,
1928 dir_pos,
1929 &empty_file_offset,
1930 &empty_entry_count);
1931 }
1932
1933 if ( retval == RC_OK
1934 && create_node) {
1935 switch (name_type) {
1936 case MSDOS_NAME_SHORT:
1937 name_len_for_save = msdos_filename_utf8_to_short_name_for_save (
1938 converter,
1939 name_utf8,
1940 name_utf8_len,
1941 buffer,
1942 MSDOS_SHORT_NAME_LEN);
1943 if (name_len_for_save > 0 ) {
1944 lfn_entries = 0;
1945 }
1946 else
1947 retval = -1;
1948 break;
1949 case MSDOS_NAME_LONG:
1950 name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
1951 converter,
1952 name_utf8,
1953 name_utf8_len,
1954 buffer,
1955 buffer_size);
1956 if (name_len_for_save > 0) {
1957 lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
1958 / MSDOS_LFN_ENTRY_SIZE;
1959 }
1960 else
1961 retval = -1;
1962 break;
1963 default:
1964 errno = EINVAL;
1965 retval = -1;
1966 break;
1967 }
1968
1969 if (retval == RC_OK)
1970 retval = msdos_add_file (
1971 buffer,
1972 name_type,
1973 fs_info,
1974 fat_fd,
1975 bts2rd,
1976 lfn_entries,
1977 name_dir_entry,
1978 dir_pos,
1979 empty_file_offset,
1980 empty_entry_count
1981 );
1982 }
1983
1984 return retval;
1985 }
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006 int msdos_find_node_by_cluster_num_in_fat_file(
2007 rtems_filesystem_mount_table_entry_t *mt_entry,
2008 fat_file_fd_t *fat_fd,
2009 uint32_t cl4find,
2010 fat_dir_pos_t *dir_pos,
2011 char *dir_entry
2012 )
2013 {
2014 int rc = RC_OK;
2015 ssize_t ret = 0;
2016 msdos_fs_info_t *fs_info = mt_entry->fs_info;
2017 uint32_t bts2rd = 0;
2018 uint32_t i = 0, j = 0;
2019
2020 if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
2021 (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
2022 bts2rd = fat_fd->fat_file_size;
2023 else
2024 bts2rd = fs_info->fat.vol.bpc;
2025
2026 while ((ret = fat_file_read(&fs_info->fat, fat_fd, j * bts2rd, bts2rd,
2027 fs_info->cl_buf)) != FAT_EOF)
2028 {
2029 if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
2030 rtems_set_errno_and_return_minus_one( EIO );
2031
2032 assert(ret == bts2rd);
2033
2034 for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
2035 {
2036 char* entry = (char*) fs_info->cl_buf + i;
2037
2038
2039 if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
2040 MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
2041 return MSDOS_NAME_NOT_FOUND_ERR;
2042
2043
2044 if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
2045 MSDOS_THIS_DIR_ENTRY_EMPTY)
2046 continue;
2047
2048
2049 if (MSDOS_EXTRACT_CLUSTER_NUM(entry) == cl4find)
2050 {
2051
2052 rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM, j * bts2rd,
2053 &dir_pos->sname.cln);
2054 if (rc != RC_OK)
2055 return rc;
2056
2057 dir_pos->sname.ofs = i;
2058 dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
2059 dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
2060
2061 memcpy(dir_entry, entry,
2062 MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
2063 return RC_OK;
2064 }
2065 }
2066 j++;
2067 }
2068 return MSDOS_NAME_NOT_FOUND_ERR;
2069 }
2070
2071 int
2072 msdos_sync(rtems_libio_t *iop)
2073 {
2074 int rc = RC_OK;
2075 msdos_fs_info_t *fs_info = iop->pathinfo.mt_entry->fs_info;
2076
2077 msdos_fs_lock(fs_info);
2078
2079 rc = fat_sync(&fs_info->fat);
2080
2081 msdos_fs_unlock(fs_info);
2082 return rc;
2083 }