source: rtems/cpukit/libfs/src/dosfs/msdos_misc.c @ d50ab079

5
Last change on this file since d50ab079 was d50ab079, checked in by Sebastian Huber <sebastian.huber@…>, on 03/16/17 at 14:12:20

dosfs: Fix file name search

Do not use our long file name entry count to optimize the file name
search. The Unicode comparison must be taken into account.

Update #2939.

  • Property mode set to 100644
File size: 63.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Miscellaneous Routines Implementation for MSDOS FileSystem
5 * @ingroup libfs
6 */
7
8/*
9 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
10 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
11 *
12 *  Modifications to support UTF-8 in the file system are
13 *  Copyright (c) 2013 embedded brains GmbH.
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19
20#define MSDOS_TRACE 1
21
22#if HAVE_CONFIG_H
23#include "config.h"
24#endif
25
26#include <stdlib.h>
27#include <ctype.h>
28#include <sys/time.h>
29#include <unistd.h>
30#include <string.h>
31#include <assert.h>
32#include <errno.h>
33#include <inttypes.h>
34#include <rtems/libio_.h>
35
36#include "fat.h"
37#include "fat_fat_operations.h"
38#include "fat_file.h"
39
40#include "msdos.h"
41
42
43#include <stdio.h>
44
45#define MSDOS_LFN_ENTRY_SIZE \
46  (MSDOS_LFN_LEN_PER_ENTRY * MSDOS_NAME_LFN_BYTES_PER_CHAR)
47
48#define MSDOS_LFN_ENTRY_SIZE_UTF8 \
49  ((MSDOS_LFN_LEN_PER_ENTRY + 1 ) * MSDOS_NAME_LFN_BYTES_PER_CHAR \
50    * MSDOS_NAME_MAX_UTF8_BYTES_PER_CHAR)
51
52/*
53 * External strings. Saves space this way.
54 */
55const char *const MSDOS_DOT_NAME    = ".          ";
56const char *const MSDOS_DOTDOT_NAME = "..         ";
57
58uint8_t
59msdos_lfn_checksum(const void *entry)
60{
61    const uint8_t *name;
62    uint8_t        cs;
63    int            i;
64
65    name = (const uint8_t *) MSDOS_DIR_NAME(entry);
66    cs = 0;
67
68    for (i = 0; i < MSDOS_SHORT_NAME_LEN; ++i) {
69        cs = ((cs & 1) ? 0x80 : 0) + (cs >> 1) + name[i];
70    }
71
72    return cs;
73}
74
75/* msdos_is_valid_name_char --
76 *     Routine to check the character in a file or directory name.
77 *     The characters support in the short file name are letters,
78 *     digits, or characters with code points values greater than
79 *     127 (not sure what this last is) plus the following special
80 *     characters "$%'-_@~`!(){}^#&". The must be uppercase.
81 *
82 *     The following 6 characters are allowed in a long names,
83 *     " +,;=[]" including a space and lower case letters.
84 *
85 * PARAMETERS:
86 *     ch        - character to check.
87 *
88 * RETURNS:
89 *     MSDOS_NAME_INVALID - Not valid in a long or short name.
90 *     MSDOS_NAME_SHORT   - Valid in a short name or long name.
91 *     MSDOS_NAME_LONG    - Valid in a long name only.
92 *
93 */
94static msdos_name_type_t
95msdos_is_valid_name_char(const char ch)
96{
97    if (strchr(" +,;=[]", ch) != NULL)
98        return MSDOS_NAME_LONG;
99
100    if ((ch == '.') || isalnum((unsigned char)ch) ||
101        (strchr("$%'-_@~`!(){}^#&", ch) != NULL) || (unsigned char) ch > 127)
102        return MSDOS_NAME_SHORT;
103
104    return MSDOS_NAME_INVALID;
105}
106
107/* msdos_short_hex_number --
108 *     Routine to set the hex number in the SFN.
109 *
110 * PARAMETERS:
111 *     name      - name to change
112 *     num       - number to set
113 *
114 * RETURNS:
115 *     nothing
116 *
117 */
118static void
119msdos_short_name_hex(char* sfn, uint32_t num)
120{
121    static const char* hex = "0123456789ABCDEF";
122    char* c = MSDOS_DIR_NAME(sfn);
123    int   i;
124    for (i = 0; i < 2; i++, c++)
125      if ((*c == ' ') || (*c == '.'))
126        *c = '_';
127    for (i = 0; i < 4; i++, c++)
128      *c = hex[(num >> ((3 - i) * 4)) & 0xf];
129    *c++ = '~';
130    *c   = '1';
131}
132
133/* msdos_name_type --
134 *     Routine the type of file name.
135 *
136 * PARAMETERS:
137 *     name      - name to check
138 *
139 * RETURNS:
140 *     true the name is long, else the name is short.
141 *
142 */
143#define MSDOS_NAME_TYPE_PRINT 0
144static msdos_name_type_t
145msdos_name_type(const char *name, int name_len)
146{
147    bool lowercase = false;
148    bool uppercase = false;
149    int  dot_at = -1;
150    int  count = 0;
151
152    while (*name && (count < name_len))
153    {
154        bool is_dot = *name == '.';
155        msdos_name_type_t type = msdos_is_valid_name_char(*name);
156
157#if MSDOS_NAME_TYPE_PRINT
158        printf ("MSDOS_NAME_TYPE: c:%02x type:%d\n", *name, type);
159#endif
160
161        if ((type == MSDOS_NAME_INVALID) || (type == MSDOS_NAME_LONG))
162            return type;
163
164        if (dot_at >= 0)
165        {
166            if (is_dot || ((count - dot_at) > 3))
167            {
168#if MSDOS_NAME_TYPE_PRINT
169                printf ("MSDOS_NAME_TYPE: LONG[1]: is_dot:%d, at:%d cnt\n",
170                        is_dot, dot_at, count);
171#endif
172                return MSDOS_NAME_LONG;
173            }
174        }
175        else
176        {
177            if (count == 8 && !is_dot)
178            {
179#if MSDOS_NAME_TYPE_PRINT
180                printf ("MSDOS_NAME_TYPE: LONG[2]: is_dot:%d, at:%d cnt\n",
181                        is_dot, dot_at, count);
182#endif
183                return MSDOS_NAME_LONG;
184            }
185        }
186
187        if (is_dot)
188            dot_at = count;
189        else if ((*name >= 'A') && (*name <= 'Z'))
190            uppercase = true;
191        else if ((*name >= 'a') && (*name <= 'z'))
192            lowercase = true;
193
194        count++;
195        name++;
196    }
197
198    if (lowercase && uppercase)
199    {
200#if MSDOS_NAME_TYPE_PRINT
201        printf ("MSDOS_NAME_TYPE: LONG[3]\n");
202#endif
203        return MSDOS_NAME_LONG;
204    }
205
206#if MSDOS_NAME_TYPE_PRINT
207    printf ("MSDOS_NAME_TYPE: SHORT[1]\n");
208#endif
209    return MSDOS_NAME_SHORT;
210}
211
212/* msdos_long_to_short --
213 *     Routine to creates a short name from a long. Start the end of the
214 *
215 * PARAMETERS:
216 *     name      - name to check
217 *
218 * RETURNS:
219 *     true the name is long, else the name is short.
220 *
221 */
222#define MSDOS_L2S_PRINT 0
223msdos_name_type_t
224msdos_long_to_short(rtems_dosfs_convert_control     *converter,
225                    const char                      *lfn,
226                    int                              lfn_len,
227                    char                            *sfn,
228                    int                              sfn_len)
229{
230    msdos_name_type_t type;
231    int               eno = 0;
232    int               i;
233    ssize_t           short_filename_length = sfn_len;
234    void             *buffer = converter->buffer.data;
235    size_t            codepage_name_len = converter->buffer.size;
236
237    /*
238     * Fill with spaces. This is how a short directory entry is padded.
239     */
240    memset (sfn, ' ', sfn_len);
241
242    /*
243     * Handle '.' and '..' specially.
244     */
245    if ((lfn[0] == '.') && (lfn_len == 1))
246    {
247        sfn[0] = '.';
248#if MSDOS_L2S_PRINT
249        printf ("MSDOS_L2S: SHORT[1]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
250#endif
251        return MSDOS_NAME_SHORT;
252    }
253
254    if ((lfn[0] == '.') && (lfn[1] == '.') && (lfn_len == 2))
255    {
256        sfn[0] = sfn[1] = '.';
257#if MSDOS_L2S_PRINT
258        printf ("MSDOS_L2S: SHORT[2]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
259#endif
260        return MSDOS_NAME_SHORT;
261    }
262
263    /*
264     * Filenames with only blanks and dots are not allowed!
265     */
266    for (i = 0; i < lfn_len; i++)
267        if ((lfn[i] != ' ') && (lfn[i] != '.'))
268            break;
269
270    if (i == lfn_len)
271    {
272#if MSDOS_L2S_PRINT
273        printf ("MSDOS_L2S: INVALID[1]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
274#endif
275        return MSDOS_NAME_INVALID;
276    }
277
278    /*
279     * Is this a short name ?
280     */
281
282    eno = (*converter->handler->utf8_to_codepage) (
283        converter,
284        (const uint8_t*)&lfn[0],
285        lfn_len,
286        buffer,
287        &codepage_name_len);
288    if (eno == EINVAL)
289    {
290        eno = 0;
291        type = MSDOS_NAME_LONG;
292    }
293    else
294    {
295        type = msdos_name_type (
296            buffer,
297            codepage_name_len);
298    }
299
300    if (type != MSDOS_NAME_INVALID)
301    {
302        short_filename_length = msdos_filename_utf8_to_short_name_for_save (
303            converter,
304            (const uint8_t*)lfn,
305            lfn_len,
306            sfn,
307            short_filename_length);
308        if (short_filename_length < 0 ) {
309            type = MSDOS_NAME_INVALID;
310        }
311#if MSDOS_L2S_PRINT
312        printf ("MSDOS_L2S: TYPE:%d lfn:'%s' SFN:'%s'\n", type, lfn, sfn);
313#endif
314    }
315    else
316    {
317#if MSDOS_L2S_PRINT
318        printf ("MSDOS_L2S: INVALID[2]: lfn:'%s' SFN:'%s'\n", lfn, sfn);
319#endif
320    }
321
322    return type;
323}
324
325/* msdos_find_name --
326 *     Find the node which correspondes to the name, open fat-file which
327 *     correspondes to the found node and close fat-file which correspondes
328 *     to the node we searched in.
329 *
330 * PARAMETERS:
331 *     parent_loc - parent node description
332 *     name       - name to find
333 *
334 * RETURNS:
335 *     RC_OK and updated 'parent_loc' on success, or -1 if error
336 *     occured (errno set apropriately)
337 *
338 */
339int
340msdos_find_name(
341    rtems_filesystem_location_info_t *parent_loc,
342    const char                       *name,
343    int                               name_len
344    )
345{
346    int                rc = RC_OK;
347    msdos_fs_info_t   *fs_info = parent_loc->mt_entry->fs_info;
348    fat_file_fd_t     *fat_fd = NULL;
349    msdos_name_type_t  name_type;
350    fat_dir_pos_t      dir_pos;
351    unsigned short     time_val = 0;
352    unsigned short     date = 0;
353    char               node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
354
355    memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
356
357    name_type = msdos_long_to_short (
358        fs_info->converter,
359        name,
360        name_len,
361        MSDOS_DIR_NAME(node_entry),
362        MSDOS_NAME_MAX);
363
364    /*
365     * find the node which corresponds to the name in the directory pointed by
366     * 'parent_loc'
367     */
368    rc = msdos_get_name_node(parent_loc, false, name, name_len, name_type,
369                             &dir_pos, node_entry);
370    if (rc != RC_OK)
371        return rc;
372
373    if (((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_VOLUME_ID) ||
374        ((*MSDOS_DIR_ATTR(node_entry) & MSDOS_ATTR_LFN_MASK) == MSDOS_ATTR_LFN))
375        return MSDOS_NAME_NOT_FOUND_ERR;
376
377    /* open fat-file corresponded to the found node */
378    rc = fat_file_open(&fs_info->fat, &dir_pos, &fat_fd);
379    if (rc != RC_OK)
380        return rc;
381
382    fat_fd->dir_pos = dir_pos;
383
384    /*
385     * I don't like this if, but: we should do it, or should write new file
386     * size and first cluster num to the disk after each write operation
387     * (even if one byte is written  - that is TOO slow) because
388     * otherwise real values of these fields stored in fat-file descriptor
389     * may be accidentally rewritten with wrong values stored on the disk
390     */
391    if (fat_fd->links_num == 1)
392    {
393        fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
394
395        time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
396        date = *MSDOS_DIR_WRITE_DATE(node_entry);
397
398        fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(date), CF_LE_W(time_val));
399
400        time_val = *MSDOS_DIR_CRT_TIME(node_entry);
401        date = *MSDOS_DIR_CRT_DATE(node_entry);
402
403        fat_fd->ctime = msdos_date_dos2unix(CF_LE_W(date), CF_LE_W(time_val));
404
405        if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
406        {
407            fat_fd->fat_file_type = FAT_DIRECTORY;
408            fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
409
410            rc = fat_file_size(&fs_info->fat, fat_fd);
411            if (rc != RC_OK)
412            {
413                fat_file_close(&fs_info->fat, fat_fd);
414                return rc;
415            }
416        }
417        else
418        {
419            fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
420            fat_fd->fat_file_type = FAT_FILE;
421            fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
422        }
423
424        /* these data is not actual for zero-length fat-file */
425        fat_fd->map.file_cln = 0;
426        fat_fd->map.disk_cln = fat_fd->cln;
427
428        if ((fat_fd->fat_file_size != 0) &&
429            (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
430        {
431            fat_fd->map.last_cln = fat_fd->cln;
432        }
433        else
434        {
435            fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
436        }
437    }
438
439    /* close fat-file corresponded to the node we searched in */
440    rc = fat_file_close(&fs_info->fat, parent_loc->node_access);
441    if (rc != RC_OK)
442    {
443        fat_file_close(&fs_info->fat, fat_fd);
444        return rc;
445    }
446
447    /* update node_info_ptr field */
448    parent_loc->node_access = fat_fd;
449
450    return rc;
451}
452
453/* msdos_get_name_node --
454 *     This routine is used in two ways: for a new node creation (a) or for
455 *     search the node which correspondes to the name parameter (b).
456 *     In case (a) 'name' should be set up to NULL and 'name_dir_entry' should
457 *     point to initialized 32 bytes structure described a new node.
458 *     In case (b) 'name' should contain a valid string.
459 *
460 *     (a): reading fat-file which correspondes to directory we are going to
461 *          create node in. If free slot is found write contents of
462 *          'name_dir_entry' into it. If reach end of fat-file and no free
463 *          slot found, write 32 bytes to the end of fat-file.
464 *
465 *     (b): reading fat-file which correspondes to directory and trying to
466 *          find slot with the name field == 'name' parameter
467 *
468 *
469 * PARAMETERS:
470 *     parent_loc     - node description to create node in or to find name in
471 *     name           - NULL or name to find
472 *     paux           - identify a node location on the disk -
473 *                      cluster num and offset inside the cluster
474 *     short_dir_entry - node to create/placeholder for found node (IN/OUT)
475 *
476 * RETURNS:
477 *     RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if
478 *     error occured (errno set apropriately)
479 *
480 */
481int
482msdos_get_name_node(
483    const rtems_filesystem_location_info_t *parent_loc,
484    bool                                    create_node,
485    const char                             *name,
486    int                                     name_len,
487    msdos_name_type_t                       name_type,
488    fat_dir_pos_t                          *dir_pos,
489    char                                   *name_dir_entry
490    )
491{
492    int              rc = RC_OK;
493    fat_file_fd_t   *fat_fd = parent_loc->node_access;
494    uint32_t         dotdot_cln = 0;
495
496    /* find name in fat-file which corresponds to the directory */
497    rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd,
498                                     create_node, (const uint8_t*)name, name_len, name_type,
499                                     dir_pos, name_dir_entry);
500    if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
501        return rc;
502
503    if (!create_node)
504    {
505        /* if we search for valid name and name not found -> return */
506        if (rc == MSDOS_NAME_NOT_FOUND_ERR)
507            return rc;
508
509        /*
510         * if we have deal with ".." - it is a special case :(((
511         *
512         * Really, we should return cluster num and offset not of ".." slot, but
513         * slot which correspondes to real directory name.
514         */
515        if (rc == RC_OK)
516        {
517            if (strncmp(name, "..", 2) == 0)
518            {
519                dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry));
520
521                /* are we right under root dir ? */
522                if (dotdot_cln == 0)
523                {
524                    /*
525                     * we can relax about first_char field - it never should be
526                     * used for root dir
527                     */
528                    fat_dir_pos_init(dir_pos);
529                    dir_pos->sname.cln = FAT_ROOTDIR_CLUSTER_NUM;
530                }
531                else
532                {
533                    rc =
534                        msdos_get_dotdot_dir_info_cluster_num_and_offset(parent_loc->mt_entry,
535                                                                         dotdot_cln,
536                                                                         dir_pos,
537                                                                         name_dir_entry);
538                    if (rc != RC_OK)
539                        return rc;
540                }
541            }
542        }
543    }
544    return rc;
545}
546
547/*
548 * msdos_get_dotdot_dir_info_cluster_num_and_offset
549 *
550 * Unfortunately, in general, we cann't work here in fat-file ideologic
551 * (open fat_file "..", get ".." and ".", open "..", find an entry ...)
552 * because if we open
553 * fat-file ".." it may happend that we have two different fat-file
554 * descriptors ( for real name of directory and ".." name ) for a single
555 * file  ( cluster num of both pointers to the same cluster )
556 * But...we do it because we protected by semaphore
557 *
558 */
559
560/* msdos_get_dotdot_dir_info_cluster_num_and_offset --
561 *     Get cluster num and offset not of ".." slot, but slot which correspondes
562 *     to real directory name.
563 *
564 * PARAMETERS:
565 *     mt_entry       - mount table entry
566 *     cln            - data cluster num extracted drom ".." slot
567 *     paux           - identify a node location on the disk -
568 *                      number of cluster and offset inside the cluster
569 *     dir_entry      - placeholder for found node
570 *
571 * RETURNS:
572 *     RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured
573 *     (errno set apropriately)
574 *
575 */
576int
577msdos_get_dotdot_dir_info_cluster_num_and_offset(
578    rtems_filesystem_mount_table_entry_t *mt_entry,
579    uint32_t                              cln,
580    fat_dir_pos_t                        *dir_pos,
581    char                                 *dir_entry
582    )
583{
584    int              rc = RC_OK;
585    msdos_fs_info_t *fs_info = mt_entry->fs_info;
586    fat_file_fd_t   *fat_fd = NULL;
587    char             dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
588    char             dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
589    uint32_t         cl4find = 0;
590    rtems_dosfs_convert_control *converter = fs_info->converter;
591
592    /*
593     * open fat-file corresponded to ".."
594     */
595    rc = fat_file_open(&fs_info->fat, dir_pos, &fat_fd);
596    if (rc != RC_OK)
597        return rc;
598
599    fat_fd->cln = cln;
600    fat_fd->fat_file_type = FAT_DIRECTORY;
601    fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
602
603    fat_fd->map.file_cln = 0;
604    fat_fd->map.disk_cln = fat_fd->cln;
605
606    rc = fat_file_size(&fs_info->fat, fat_fd);
607    if (rc != RC_OK)
608    {
609        fat_file_close(&fs_info->fat, fat_fd);
610        return rc;
611    }
612
613    /* find "." node in opened directory */
614    memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
615    msdos_long_to_short(
616        converter,
617        ".", 1, dot_node, MSDOS_SHORT_NAME_LEN);
618    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)".", 1,
619                                     MSDOS_NAME_SHORT, dir_pos, dot_node);
620
621    if (rc != RC_OK)
622    {
623        fat_file_close(&fs_info->fat, fat_fd);
624        return rc;
625    }
626
627    /* find ".." node in opened directory */
628    memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
629    msdos_long_to_short(
630        converter,
631        "..", 2, dotdot_node, MSDOS_SHORT_NAME_LEN);
632    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, false, (const uint8_t*)"..", 2,
633                                     MSDOS_NAME_SHORT, dir_pos,
634                                     dotdot_node);
635
636    if (rc != RC_OK)
637    {
638        fat_file_close(&fs_info->fat, fat_fd);
639        return rc;
640    }
641
642    cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
643
644    /* close fat-file corresponded to ".." directory */
645    rc = fat_file_close(&fs_info->fat, fat_fd);
646    if ( rc != RC_OK )
647        return rc;
648
649    if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
650    {
651        /*
652         * we handle root dir for all FAT types in the same way with the
653         * ordinary directories ( through fat_file_* calls )
654         */
655        fat_dir_pos_init(dir_pos);
656        dir_pos->sname.cln = FAT_ROOTDIR_CLUSTER_NUM;
657    }
658
659    /* open fat-file corresponded to second ".." */
660    rc = fat_file_open(&fs_info->fat, dir_pos, &fat_fd);
661    if (rc != RC_OK)
662        return rc;
663
664    if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
665        fat_fd->cln = fs_info->fat.vol.rdir_cl;
666    else
667        fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
668
669    fat_fd->fat_file_type = FAT_DIRECTORY;
670    fat_fd->size_limit = MSDOS_MAX_DIR_LENGTH;
671
672    fat_fd->map.file_cln = 0;
673    fat_fd->map.disk_cln = fat_fd->cln;
674
675    rc = fat_file_size(&fs_info->fat, fat_fd);
676    if (rc != RC_OK)
677    {
678        fat_file_close(&fs_info->fat, fat_fd);
679        return rc;
680    }
681
682    /* in this directory find slot with specified cluster num */
683    rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
684                                                    dir_pos, dir_entry);
685    if (rc != RC_OK)
686    {
687        fat_file_close(&fs_info->fat, fat_fd);
688        return rc;
689    }
690    rc = fat_file_close(&fs_info->fat, fat_fd);
691    return rc;
692}
693
694
695/* fat_file_write_time_and_date --
696 *     Write last write date and time for a file to the disk (to corresponded
697 *     32bytes node)
698 *
699 * PARAMETERS:
700 *     fs_info  - fat fs info
701 *     fat_fd   - fat-file descriptor
702 *
703 * RETURNS:
704 *     RC_OK on success, or -1 if error occured (errno set apropriately).
705 *
706 */
707int
708fat_file_write_time_and_date(
709    fat_fs_info_t                        *fs_info,
710    fat_file_fd_t                        *fat_fd
711    )
712{
713    int              rc = RC_OK;
714    ssize_t          ret;
715    uint16_t         time_val;
716    uint16_t         date;
717    uint32_t         sec = 0;
718    uint32_t         byte = 0;
719
720    /*
721     * calculate input for fat_sector_write: convert (cluster num, offset) to
722     * (sector num, new offset)
723     */
724    sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->dir_pos.sname.cln);
725    sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
726    /* byte points to start of 32bytes structure */
727    byte = fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1);
728
729    msdos_date_unix2dos(fat_fd->mtime, &date, &time_val);
730
731    time_val = CT_LE_W(time_val);
732    ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_WTIME_OFFSET,
733                           2, (char *)(&time_val));
734    if ( ret < 0 )
735        rc = -1;
736
737    date = CT_LE_W(date);
738    ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_WDATE_OFFSET,
739                           2, (char *)(&date));
740    if ( ret < 0 )
741        rc = -1;
742
743    ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_ADATE_OFFSET,
744                           2, (char *)(&date));
745    if ( ret < 0 )
746        rc = -1;
747
748    msdos_date_unix2dos(fat_fd->ctime, &date, &time_val);
749
750    time_val = CT_LE_W(time_val);
751    ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_CTIME_OFFSET,
752                           2, (char *)(&time_val));
753    if ( ret < 0 )
754        rc = -1;
755
756    date = CT_LE_W(date);
757    ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_CDATE_OFFSET,
758                           2, (char *)(&date));
759    if ( ret < 0 )
760        rc = -1;
761
762    return rc;
763}
764
765/* fat_set_first_cluster_num --
766 *     Write number of first cluster of the file to the disk (to corresponded
767 *     32bytes slot)
768 *
769 * PARAMETERS:
770 *     fs_info  - fat fs info
771 *     fat_fd   - fat-file descriptor
772 *
773 * RETURNS:
774 *     RC_OK on success, or -1 if error occured
775 *
776 */
777int
778fat_file_write_first_cluster_num(
779    fat_fs_info_t                        *fs_info,
780    fat_file_fd_t                        *fat_fd
781    )
782{
783    ssize_t          ret1 = 0, ret2 = 0;
784    uint32_t         new_cln = fat_fd->cln;
785    uint16_t         le_cl_low = 0;
786    uint16_t         le_cl_hi = 0;
787    uint32_t         sec = 0;
788    uint32_t         byte = 0;
789
790    /*
791     * calculate input for fat_sector_write: convert (cluster num, offset) to
792     * (sector num, new offset)
793     */
794    sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->dir_pos.sname.cln);
795    sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
796    /* byte from points to start of 32bytes structure */
797    byte = fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1);
798
799    le_cl_low = CT_LE_W((uint16_t  )(new_cln & 0x0000FFFF));
800    ret1 = fat_sector_write(fs_info, sec,
801                            byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
802                            (char *)(&le_cl_low));
803    le_cl_hi = CT_LE_W((uint16_t  )((new_cln & 0xFFFF0000) >> 16));
804    ret2 = fat_sector_write(fs_info, sec,
805                            byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
806                            (char *)(&le_cl_hi));
807    if ( (ret1 < 0) || (ret2 < 0) )
808        return -1;
809
810    return RC_OK;
811}
812
813
814/* fat_set_file size --
815 *     Write file size of the file to the disk (to corresponded 32bytes slot)
816 *
817 * PARAMETERS:
818 *     fs_info  - fat fs info
819 *     fat_fd   - fat-file descriptor
820 *
821 * RETURNS:
822 *     RC_OK on success, or -1 if error occured (errno set apropriately).
823 *
824 */
825int
826fat_file_write_file_size(
827    fat_fs_info_t                        *fs_info,
828    fat_file_fd_t                        *fat_fd
829    )
830{
831    ssize_t          ret = 0;
832    uint32_t         le_new_length = 0;
833    uint32_t         sec = 0;
834    uint32_t         byte = 0;
835
836    sec = fat_cluster_num_to_sector_num(fs_info, fat_fd->dir_pos.sname.cln);
837    sec += (fat_fd->dir_pos.sname.ofs >> fs_info->vol.sec_log2);
838    byte = (fat_fd->dir_pos.sname.ofs & (fs_info->vol.bps - 1));
839
840    if (fat_fd->fat_file_type == FAT_DIRECTORY) {
841      le_new_length = CT_LE_L(0);
842    } else {
843      le_new_length = CT_LE_L(fat_fd->fat_file_size);
844    }
845
846    ret = fat_sector_write(fs_info, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
847                           (char *)(&le_new_length));
848    if ( ret < 0 )
849        return -1;
850
851    return RC_OK;
852}
853
854/*
855 * We should not check whether this routine is called for root dir - it
856 * never can happend
857 */
858
859/* msdos_set_first_char4file_name --
860 *     Write first character of the name of the file to the disk (to
861 *     corresponded 32bytes slot)
862 *
863 * PARAMETERS:
864 *     mt_entry - mount table entry
865 *     cl       - number of cluster
866 *     ofs      - offset inside cluster
867 *     fchar    - character to set up
868 *
869 * RETURNS:
870 *     RC_OK on success, or -1 if error occured (errno set apropriately)
871 *
872 */
873int
874msdos_set_first_char4file_name(
875    rtems_filesystem_mount_table_entry_t *mt_entry,
876    fat_dir_pos_t                        *dir_pos,
877    unsigned char                         fchar
878    )
879{
880    ssize_t          ret;
881    msdos_fs_info_t *fs_info = mt_entry->fs_info;
882    uint32_t         dir_block_size;
883    fat_pos_t        start = dir_pos->lname;
884    fat_pos_t        end = dir_pos->sname;
885
886    if ((end.cln == fs_info->fat.vol.rdir_cl) &&
887        (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
888      dir_block_size = fs_info->fat.vol.rdir_size;
889    else
890      dir_block_size = fs_info->fat.vol.bpc;
891
892    if (dir_pos->lname.cln == FAT_FILE_SHORT_NAME)
893      start = dir_pos->sname;
894
895    /*
896     * We handle the changes directly due the way the short file
897     * name code was written rather than use the fat_file_write
898     * interface.
899     */
900    while (true)
901    {
902      uint32_t sec = (fat_cluster_num_to_sector_num(&fs_info->fat, start.cln) +
903                      (start.ofs >> fs_info->fat.vol.sec_log2));
904      uint32_t byte = (start.ofs & (fs_info->fat.vol.bps - 1));
905
906      ret = fat_sector_write(&fs_info->fat, sec, byte + MSDOS_FILE_NAME_OFFSET,
907                             1, &fchar);
908      if (ret < 0)
909        return -1;
910
911      if ((start.cln == end.cln) && (start.ofs == end.ofs))
912        break;
913
914      start.ofs += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
915      if (start.ofs >= dir_block_size)
916      {
917        int rc;
918        if ((end.cln == fs_info->fat.vol.rdir_cl) &&
919            (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
920          break;
921        rc = fat_get_fat_cluster(&fs_info->fat, start.cln, &start.cln);
922        if ( rc != RC_OK )
923          return rc;
924        start.ofs = 0;
925      }
926    }
927
928    return  RC_OK;
929}
930
931/* msdos_dir_is_empty --
932 *     Check whether directory which correspondes to the fat-file descriptor is
933 *     empty.
934 *
935 * PARAMETERS:
936 *     mt_entry - mount table entry
937 *     fat_fd   - fat-file descriptor
938 *     ret_val  - placeholder for result
939 *
940 * RETURNS:
941 *     RC_OK on success, or -1 if error occured
942 *
943 */
944int
945msdos_dir_is_empty(
946    rtems_filesystem_mount_table_entry_t *mt_entry,
947    fat_file_fd_t                        *fat_fd,
948    bool                                 *ret_val
949    )
950{
951    ssize_t          ret = 0;
952    msdos_fs_info_t *fs_info = mt_entry->fs_info;
953    uint32_t         j = 0, i = 0;
954
955    /* dir is not empty */
956    *ret_val = false;
957
958    while ((ret = fat_file_read(&fs_info->fat, fat_fd, j * fs_info->fat.vol.bps,
959                                  fs_info->fat.vol.bps,
960                                  fs_info->cl_buf)) != FAT_EOF)
961    {
962        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
963            return -1;
964
965        assert(ret == fs_info->fat.vol.bps);
966
967        /* have to look at the DIR_NAME as "raw" 8-bit data */
968        for (i = 0;
969             i < fs_info->fat.vol.bps;
970             i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
971        {
972            char* entry = (char*) fs_info->cl_buf + i;
973
974            /*
975             * If the entry is empty, a long file name entry, or '.' or '..'
976             * then consider it as empty.
977             *
978             * Just ignore long file name entries. They must have a short entry to
979             * be valid.
980             */
981            if (((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
982                 MSDOS_THIS_DIR_ENTRY_EMPTY) ||
983                ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
984                 MSDOS_ATTR_LFN) ||
985                (strncmp(MSDOS_DIR_NAME((entry)), MSDOS_DOT_NAME,
986                         MSDOS_SHORT_NAME_LEN) == 0) ||
987                (strncmp(MSDOS_DIR_NAME((entry)),
988                         MSDOS_DOTDOT_NAME,
989                         MSDOS_SHORT_NAME_LEN) == 0))
990                continue;
991
992            /*
993             * Nothing more to look at.
994             */
995            if ((*MSDOS_DIR_NAME(entry)) ==
996                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
997            {
998                *ret_val = true;
999                return RC_OK;
1000            }
1001
1002            /*
1003             * Short file name entries mean not empty.
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
1014static int
1015msdos_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     * We get the entry we looked for - fill the position
1033     * structure and the 32 bytes of the short entry
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
1063ssize_t
1064msdos_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/*  msdos_format_dirent_with_dot --
1096 *      This routine convert a (short) MSDOS filename as present on disk
1097 *      (fixed 8+3 characters, filled with blanks, without separator dot)
1098 *      to a "normal" format, with between 0 and 8 name chars,
1099 *      a separating dot and up to 3 extension characters
1100 *   Rules to work:
1101 *      - copy any (0-8) "name" part characters that are non-blank
1102 *      - if an extension exists, append a dot
1103 *      - copy any (0-3) non-blank extension characters
1104 *      - append a '\0' (dont count it for the rturn code
1105 *
1106 * PARAMETERS:
1107 *     dst: pointer to destination char array (must be big enough)
1108 *     src: pointer to source characters
1109 *
1110 *
1111 * RETURNS:
1112 *     the number of bytes (without trailing '\0'(written to destination
1113 */
1114ssize_t
1115msdos_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   * find last non-blank character of base name
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   * copy base name to destination
1130   */
1131  src_tmp = src;
1132  len = i;
1133  while (i-- > 0) {
1134    *dst++ = tolower((unsigned char)(*src_tmp++));
1135  }
1136  /*
1137   * find last non-blank character of extension
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   * extension is not empty
1146   */
1147  if (i > 0) {
1148    *dst++ = '.'; /* append dot */
1149    ++len;        /* dot */
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'; /* terminate string */
1157
1158  return len;
1159}
1160
1161static ssize_t
1162msdos_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
1203static 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
1238static ssize_t
1239msdos_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                 filename_size_remaining,
1245    bool                        *is_matching)
1246{
1247  ssize_t      size_remaining = filename_size_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 = filename_size_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
1290static int
1291msdos_find_file_in_directory (
1292    const uint8_t                        *filename_converted,
1293    const size_t                          name_len_for_compare,
1294    const size_t                          name_len_for_save,
1295    const msdos_name_type_t               name_type,
1296    msdos_fs_info_t                      *fs_info,
1297    fat_file_fd_t                        *fat_fd,
1298    const uint32_t                        bts2rd,
1299    const bool                            create_node,
1300    const unsigned int                    lfn_entries,
1301    char                                 *name_dir_entry,
1302    fat_dir_pos_t                        *dir_pos,
1303    uint32_t                             *empty_file_offset,
1304    uint32_t                             *empty_entry_count)
1305{
1306    int               rc                = RC_OK;
1307    ssize_t           bytes_read;
1308    uint32_t          dir_entry;
1309    fat_pos_t         lfn_start;
1310    uint8_t           lfn_checksum      = 0;
1311    bool              entry_matched       = false;
1312    bool              empty_space_found = false;
1313    uint32_t          entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1314    int               lfn_entry         = 0;
1315    uint8_t           entry_utf8_normalized[MSDOS_LFN_ENTRY_SIZE_UTF8];
1316    size_t            bytes_in_entry;
1317    bool              filename_matched  = false;
1318    ssize_t           filename_size_remaining = name_len_for_compare;
1319    rtems_dosfs_convert_control *converter = fs_info->converter;
1320    uint32_t          dir_offset = 0;
1321
1322    /*
1323     * Scan the directory seeing if the file is present. While
1324     * doing this see if a suitable location can be found to
1325     * create the entry if the name is not found.
1326     */
1327
1328    lfn_start.cln = lfn_start.ofs = FAT_FILE_SHORT_NAME;
1329
1330    while (   (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (dir_offset * bts2rd),
1331                                             bts2rd, fs_info->cl_buf)) != FAT_EOF
1332           && rc == RC_OK)
1333    {
1334        bool remainder_empty = false;
1335#if MSDOS_FIND_PRINT
1336        printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
1337#endif
1338
1339        if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
1340            rtems_set_errno_and_return_minus_one(EIO);
1341
1342        assert(bytes_read == bts2rd);
1343
1344        /* have to look at the DIR_NAME as "raw" 8-bit data */
1345        for (dir_entry = 0;
1346             dir_entry < bts2rd && rc == RC_OK && (! filename_matched);
1347             dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
1348        {
1349            char* entry = (char*) fs_info->cl_buf + dir_entry;
1350
1351            /*
1352             * See if the entry is empty or the remainder of the directory is
1353             * empty ? Localize to make the code read better.
1354             */
1355            bool entry_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
1356                                MSDOS_THIS_DIR_ENTRY_EMPTY);
1357            remainder_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
1358                               MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
1359#if MSDOS_FIND_PRINT
1360            printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
1361                    remainder_empty, entry_empty, dir_offset,
1362                    dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
1363#endif
1364            /*
1365             * Remember where the we are, ie the start, so we can come back
1366             * to here and write the long file name if this is the start of
1367             * a series of empty entries. If empty_entry_count is 0 then
1368             * we are currently not inside an empty series of entries. It
1369             * is a count of empty entries.
1370             */
1371            if (*empty_entry_count == 0)
1372            {
1373                *empty_file_offset = dir_offset * bts2rd + dir_entry;
1374            }
1375
1376            if (remainder_empty)
1377            {
1378#if MSDOS_FIND_PRINT
1379                printf ("MSFS:[3.1] cn:%i esf:%i\n", create_node, empty_space_found);
1380#endif
1381                /*
1382                 * If just looking and there is no more entries in the
1383                 * directory - return name-not-found
1384                 */
1385                if (!create_node)
1386                    rc = MSDOS_NAME_NOT_FOUND_ERR;
1387
1388                /*
1389                 * Lets go and write the directory entries. If we have not found
1390                 * any available space add the remaining number of entries to any that
1391                 * we may have already found that are just before this entry. If more
1392                 * are needed FAT_EOF is returned by the read and we extend the file.
1393                 */
1394                if (   !empty_space_found
1395                    && rc == RC_OK )
1396                {
1397                    *empty_entry_count +=
1398                    entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1399                    empty_space_found = true;
1400#if MSDOS_FIND_PRINT
1401                    printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_entry_count );
1402#endif
1403                }
1404                break;
1405            }
1406            else if (entry_empty)
1407            {
1408                if (create_node)
1409                {
1410                    /*
1411                     * Remainder is not empty so is this entry empty ?
1412                     */
1413                    (*empty_entry_count)++;
1414
1415                    if (*empty_entry_count == (lfn_entries + 1))
1416                        empty_space_found = true;
1417                }
1418#if MSDOS_FIND_PRINT
1419                printf ("MSFS:[4.1] esc:%li esf:%i\n",
1420                        *empty_entry_count, empty_space_found);
1421#endif
1422            }
1423            else
1424            {
1425                /*
1426                 * A valid entry so handle it.
1427                 *
1428                 * If empty space has not been found we need to start the
1429                 * count again.
1430                 */
1431                if (create_node && !empty_space_found)
1432                {
1433                    *empty_file_offset = 0;
1434                    *empty_entry_count = 0;
1435                }
1436
1437                /*
1438                 * Check the attribute to see if the entry is for a long
1439                 * file name.
1440                 */
1441                if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
1442                    MSDOS_ATTR_LFN)
1443                {
1444                    bool is_first_lfn_entry =
1445                        (lfn_start.cln == FAT_FILE_SHORT_NAME);
1446
1447/*                    int   o;*/
1448#if MSDOS_FIND_PRINT
1449                    printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
1450                            lfn_start.cln == FAT_FILE_SHORT_NAME ? 'f' : 't',
1451                            *MSDOS_DIR_ENTRY_TYPE(entry) & MSDOS_LAST_LONG_ENTRY_MASK,
1452                            *MSDOS_DIR_LFN_CHECKSUM(entry));
1453#endif
1454                    /*
1455                     * If we are not already processing a LFN see if this is
1456                     * the first entry of a LFN ?
1457                     */
1458                    if (is_first_lfn_entry)
1459                    {
1460                        entry_matched = false;
1461
1462                        /*
1463                         * The first entry must have the last long entry
1464                         * flag set.
1465                         */
1466                        if ((*MSDOS_DIR_ENTRY_TYPE(entry) &
1467                             MSDOS_LAST_LONG_ENTRY) == 0)
1468                            continue;
1469
1470                        lfn_start.cln = dir_offset;
1471                        lfn_start.ofs = dir_entry;
1472                        lfn_entry = (*MSDOS_DIR_ENTRY_TYPE(entry)
1473                            & MSDOS_LAST_LONG_ENTRY_MASK);
1474                        lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
1475
1476#if MSDOS_FIND_PRINT
1477                        printf ("MSFS:[4.3] lfn_checksum:%i\n",
1478                                lfn_checksum);
1479#endif
1480                    }
1481
1482                    /*
1483                     * If the entry number or the check sum do not match
1484                     * forget this series of long directory entries. These
1485                     * could be orphaned entries depending on the history
1486                     * of the disk.
1487                     */
1488                    if ((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.4] no match\n");
1494#endif
1495                        lfn_start.cln = FAT_FILE_SHORT_NAME;
1496                        continue;
1497                    }
1498#if MSDOS_FIND_PRINT
1499                    printf ("MSFS:[5] lfne:%i\n", lfn_entry);
1500#endif
1501                    lfn_entry--;
1502
1503                    bytes_in_entry = msdos_long_entry_to_utf8_name (
1504                        converter,
1505                        entry,
1506                        is_first_lfn_entry,
1507                        &entry_utf8_normalized[0],
1508                        sizeof (entry_utf8_normalized));
1509                    if (bytes_in_entry > 0) {
1510                        filename_size_remaining = msdos_compare_entry_against_filename (
1511                            converter,
1512                            &entry_utf8_normalized[0],
1513                            bytes_in_entry,
1514                            &filename_converted[0],
1515                            filename_size_remaining,
1516                            &entry_matched);
1517
1518                        if (filename_size_remaining < 0
1519                            || (! entry_matched)) {
1520                            filename_size_remaining = name_len_for_compare;
1521                            lfn_start.cln = FAT_FILE_SHORT_NAME;
1522                        }
1523                    } else {
1524                      lfn_start.cln = FAT_FILE_SHORT_NAME;
1525                      entry_matched   = false;
1526                    }
1527                }
1528                else
1529                {
1530#if MSDOS_FIND_PRINT
1531                    printf ("MSFS:[9.1] SFN entry, entry_matched:%i\n", entry_matched);
1532#endif
1533                    /*
1534                     * SFN entry found.
1535                     *
1536                     * If a LFN has been found and it matched check the
1537                     * entries have all been found and the checksum is
1538                     * correct. If this is the case return the short file
1539                     * name entry.
1540                     */
1541                    if (entry_matched)
1542                    {
1543                        if (lfn_entry ||
1544                            lfn_checksum != msdos_lfn_checksum(entry))
1545                            entry_matched = false;
1546                        else if (filename_size_remaining == 0) {
1547                            filename_matched = true;
1548                            rc = msdos_on_entry_found (
1549                                fs_info,
1550                                fat_fd,
1551                                bts2rd,
1552                                name_dir_entry,
1553                                entry,
1554                                dir_pos,
1555                                dir_offset,
1556                                dir_entry,
1557                                &lfn_start
1558                            );
1559                        }
1560
1561#if MSDOS_FIND_PRINT
1562                        printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
1563                                entry_matched, lfn_entry, lfn_checksum, msdos_lfn_checksum(entry));
1564#endif
1565                    } else {
1566                        bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
1567                        bytes_in_entry = msdos_short_entry_to_utf8_name (
1568                            converter,
1569                            MSDOS_DIR_NAME (entry),
1570                            &entry_utf8_normalized[0],
1571                            bytes_in_entry);
1572                        if (bytes_in_entry > 0) {
1573                            filename_size_remaining = msdos_compare_entry_against_filename (
1574                                converter,
1575                                &entry_utf8_normalized[0],
1576                                bytes_in_entry,
1577                                &filename_converted[0],
1578                                name_len_for_compare,
1579                                &entry_matched);
1580                            if (entry_matched && filename_size_remaining == 0) {
1581                                filename_matched = true;
1582                                rc = msdos_on_entry_found (
1583                                    fs_info,
1584                                    fat_fd,
1585                                    bts2rd,
1586                                    name_dir_entry,
1587                                    entry,
1588                                    dir_pos,
1589                                    dir_offset,
1590                                    dir_entry,
1591                                    &lfn_start
1592                                );
1593                            }
1594                            if (rc == RC_OK && (! filename_matched)) {
1595                                lfn_start.cln           = FAT_FILE_SHORT_NAME;
1596                                entry_matched           = false;
1597                                filename_size_remaining = name_len_for_compare;
1598                            }
1599                        } else {
1600                          lfn_start.cln           = FAT_FILE_SHORT_NAME;
1601                          entry_matched           = false;
1602                          filename_size_remaining = name_len_for_compare;
1603                        }
1604                    }
1605                }
1606            }
1607        }
1608
1609        if (filename_matched || remainder_empty)
1610            break;
1611
1612        dir_offset++;
1613    }
1614    if ( ! filename_matched ) {
1615        /*
1616         * If we are not to create the entry return a not found error.
1617         */
1618        if (!create_node)
1619            rc = MSDOS_NAME_NOT_FOUND_ERR;
1620
1621#if MSDOS_FIND_PRINT
1622        printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" efo:%"PRIu32"\n",
1623                 dir_offset, *empty_entry_count, *empty_file_offset );
1624#endif
1625    }
1626
1627    return rc;
1628}
1629
1630static int
1631msdos_get_pos(
1632    msdos_fs_info_t *fs_info,
1633    fat_file_fd_t   *fat_fd,
1634    uint32_t         bts2rd,
1635    uint32_t         file_offset,
1636    fat_pos_t       *pos
1637)
1638{
1639    pos->ofs = file_offset & (bts2rd - 1);
1640    return fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
1641                          file_offset, &pos->cln);
1642}
1643
1644static int
1645msdos_add_file (
1646    const char                           *name_converted,
1647    const msdos_name_type_t               name_type,
1648    msdos_fs_info_t                      *fs_info,
1649    fat_file_fd_t                        *fat_fd,
1650    const uint32_t                        bts2rd,
1651    const unsigned int                    lfn_entries,
1652    const char                           *name_dir_entry,
1653    fat_dir_pos_t                        *dir_pos,
1654    uint32_t                              empty_file_offset,
1655    const uint32_t                        empty_entry_count
1656)
1657{
1658    int              ret;
1659    ssize_t          bytes_written;
1660    uint8_t          lfn_checksum;
1661    int              lfn_entry;
1662    uint8_t         *entry;
1663    uint32_t         short_file_offset;
1664    uint32_t         length;
1665
1666    /*
1667     * If there is not enough space available then extend the file.
1668     */
1669    if (empty_entry_count < lfn_entries + 1)
1670    {
1671        uint32_t unused;
1672
1673        empty_file_offset = fat_fd->fat_file_size -
1674            empty_entry_count * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1675
1676        ret = fat_file_extend(&fs_info->fat,
1677                              fat_fd,
1678                              true,
1679                              fat_fd->fat_file_size + fs_info->fat.vol.bpc,
1680                              &unused);
1681        if (ret != RC_OK)
1682            return ret;
1683    }
1684
1685    if (name_type == MSDOS_NAME_LONG)
1686    {
1687        uint32_t slot;
1688
1689        /*
1690         * If a long file name calculate the checksum of the short file name
1691         * data to place in each long file name entry. First set the short
1692         * file name to the slot of the SFN entry. This will mean no clashes
1693         * in this directory.
1694         */
1695        slot = (empty_file_offset /
1696            MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1;
1697        msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
1698
1699        lfn_checksum = msdos_lfn_checksum(name_dir_entry);
1700
1701        short_file_offset = empty_file_offset + lfn_entries
1702            * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1703
1704        /* Get position of first long file name entry */
1705        ret = msdos_get_pos(fs_info, fat_fd, bts2rd, empty_file_offset,
1706                            &dir_pos->lname);
1707        if (ret != RC_OK)
1708            return ret;
1709    } else {
1710        lfn_checksum = 0;
1711        short_file_offset = empty_file_offset;
1712        dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
1713        dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
1714    }
1715
1716    /* Get position of short file name entry */
1717    ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
1718                        &dir_pos->sname);
1719
1720    /*
1721     * Handle the entry writes.
1722     */
1723    entry = fs_info->cl_buf;
1724
1725#if MSDOS_FIND_PRINT
1726    printf ("MSFS:[9] read_cluster:%d efo:%ld ese:%ld\n",
1727            read_cluster, empty_file_offset, empty_space_entry);
1728#endif
1729
1730    /* Long file name entries */
1731    for (lfn_entry = 0; lfn_entry < lfn_entries; ++lfn_entry) {
1732        uint8_t       *p;
1733        const uint8_t *n;
1734        int            i;
1735        uint8_t        fill = 0;
1736
1737        /*
1738         * Clear the entry before loading the data.
1739         */
1740        memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1741
1742        *MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
1743
1744        p = entry + 1;
1745        n = (const uint8_t *) name_converted +
1746            (lfn_entries - lfn_entry - 1) * MSDOS_LFN_ENTRY_SIZE;
1747
1748#if MSDOS_FIND_PRINT
1749        printf ("MSFS:[11] ");
1750#endif
1751        for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
1752        {
1753            if (*n != 0 || *(n + 1) != 0)
1754            {
1755                *p = *n;
1756                *(p + 1) = *(n + 1);
1757                n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
1758            }
1759            else
1760            {
1761                p [0] = fill;
1762                p [1] = fill;
1763                fill = 0xff;
1764            }
1765#if MSDOS_FIND_PRINT
1766            printf ( "'%c''%c'", *p, *(p+1) );
1767#endif
1768
1769            switch (i)
1770            {
1771                case 4:
1772                    p += 5;
1773                    break;
1774                case 10:
1775                    p += 4;
1776                    break;
1777                default:
1778                    p += 2;
1779                    break;
1780            }
1781        }
1782#if MSDOS_FIND_PRINT
1783        printf ( "\n" );
1784#endif
1785        *MSDOS_DIR_ENTRY_TYPE(entry) = lfn_entries - lfn_entry;
1786        if (lfn_entry == 0)
1787            *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
1788        *MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
1789
1790        entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1791    }
1792
1793    /* Short file name entry */
1794    memcpy(entry, name_dir_entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1795
1796    length = (lfn_entries + 1) * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1797    bytes_written = fat_file_write(&fs_info->fat, fat_fd,
1798                                   empty_file_offset,
1799                                   length, fs_info->cl_buf);
1800    if (bytes_written == (ssize_t) length)
1801        return 0;
1802    else if (bytes_written == -1)
1803        return -1;
1804    else
1805        rtems_set_errno_and_return_minus_one(EIO);
1806}
1807
1808int
1809msdos_find_name_in_fat_file (
1810    rtems_filesystem_mount_table_entry_t *mt_entry,
1811    fat_file_fd_t                        *fat_fd,
1812    bool                                  create_node,
1813    const uint8_t                        *name_utf8,
1814    int                                   name_utf8_len,
1815    msdos_name_type_t                     name_type,
1816    fat_dir_pos_t                        *dir_pos,
1817    char                                 *name_dir_entry)
1818{
1819    int                                retval                     = 0;
1820    msdos_fs_info_t                   *fs_info                    = mt_entry->fs_info;
1821    ssize_t                            name_len_for_save;
1822    ssize_t                            name_len_for_compare;
1823    uint32_t                           bts2rd                     = 0;
1824    uint32_t                           empty_file_offset          = 0;
1825    uint32_t                           empty_entry_count          = 0;
1826    unsigned int                       lfn_entries;
1827    rtems_dosfs_convert_control       *converter = fs_info->converter;
1828    void                              *buffer = converter->buffer.data;
1829    size_t                             buffer_size = converter->buffer.size;
1830
1831    assert(name_utf8_len > 0);
1832
1833    fat_dir_pos_init(dir_pos);
1834
1835
1836
1837    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
1838        (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
1839        bts2rd = fat_fd->fat_file_size;
1840    else
1841        bts2rd = fs_info->fat.vol.bpc;
1842
1843    switch ( name_type ) {
1844        case MSDOS_NAME_SHORT:
1845            name_len_for_compare = msdos_filename_utf8_to_short_name_for_compare (
1846                converter,
1847                name_utf8,
1848                name_utf8_len,
1849                buffer,
1850                MSDOS_SHORT_NAME_LEN);
1851            if (name_len_for_compare > 0) {
1852                lfn_entries = 0;
1853            }
1854            else
1855                retval = -1;
1856        break;
1857        case MSDOS_NAME_LONG:
1858            name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
1859                converter,
1860                name_utf8,
1861                name_utf8_len,
1862                buffer,
1863                buffer_size);
1864            if (name_len_for_save > 0) {
1865                lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
1866                    / MSDOS_LFN_ENTRY_SIZE;
1867                name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
1868                  converter,
1869                  name_utf8,
1870                  name_utf8_len,
1871                  buffer,
1872                  buffer_size);
1873                if (0 >= name_len_for_compare) {
1874                    retval = -1;
1875                }
1876            }
1877            else
1878                retval = -1;
1879        break;
1880        default:
1881            errno = EINVAL;
1882            retval = -1;
1883        break;
1884    }
1885    if (retval == RC_OK) {
1886      /* See if the file/directory does already exist */
1887      retval = msdos_find_file_in_directory (
1888          buffer,
1889          name_len_for_compare,
1890          name_len_for_save,
1891          name_type,
1892          fs_info,
1893          fat_fd,
1894          bts2rd,
1895          create_node,
1896          lfn_entries,
1897          name_dir_entry,
1898          dir_pos,
1899          &empty_file_offset,
1900          &empty_entry_count);
1901    }
1902    /* Create a non-existing file/directory if requested */
1903    if (   retval == RC_OK
1904        && create_node) {
1905        switch (name_type) {
1906          case MSDOS_NAME_SHORT:
1907              name_len_for_save = msdos_filename_utf8_to_short_name_for_save (
1908                  converter,
1909                  name_utf8,
1910                  name_utf8_len,
1911                  buffer,
1912                  MSDOS_SHORT_NAME_LEN);
1913              if (name_len_for_save > 0 ) {
1914                  lfn_entries = 0;
1915              }
1916              else
1917                  retval = -1;
1918          break;
1919          case MSDOS_NAME_LONG:
1920              name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
1921                  converter,
1922                  name_utf8,
1923                  name_utf8_len,
1924                  buffer,
1925                  buffer_size);
1926              if (name_len_for_save > 0) {
1927                  lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
1928                    / MSDOS_LFN_ENTRY_SIZE;
1929              }
1930              else
1931                  retval = -1;
1932          break;
1933          default:
1934              errno = EINVAL;
1935              retval = -1;
1936          break;
1937        }
1938
1939        if (retval == RC_OK)
1940            retval = msdos_add_file (
1941                buffer,
1942                name_type,
1943                fs_info,
1944                fat_fd,
1945                bts2rd,
1946                lfn_entries,
1947                name_dir_entry,
1948                dir_pos,
1949                empty_file_offset,
1950                empty_entry_count
1951            );
1952    }
1953
1954    return retval;
1955}
1956
1957
1958/* msdos_find_node_by_cluster_num_in_fat_file --
1959 *     Find node with specified number of cluster in fat-file.
1960 *
1961 * Note, not updated in the LFN change because it is only used
1962 *       for . and .. entries and these are always short.
1963 *
1964 * PARAMETERS:
1965 *     mt_entry  - mount table entry
1966 *     fat_fd    - fat-file descriptor
1967 *     cl4find   - number of cluster to find
1968 *     paux      - identify a node location on the disk -
1969 *                 cluster num and offset inside the cluster
1970 *     dir_entry - placeholder for found node
1971 *
1972 * RETURNS:
1973 *     RC_OK on success, or error code if error occured
1974 *
1975 */
1976int msdos_find_node_by_cluster_num_in_fat_file(
1977    rtems_filesystem_mount_table_entry_t *mt_entry,
1978    fat_file_fd_t                        *fat_fd,
1979    uint32_t                              cl4find,
1980    fat_dir_pos_t                        *dir_pos,
1981    char                                 *dir_entry
1982    )
1983{
1984    int              rc = RC_OK;
1985    ssize_t          ret = 0;
1986    msdos_fs_info_t *fs_info = mt_entry->fs_info;
1987    uint32_t         bts2rd = 0;
1988    uint32_t         i = 0, j = 0;
1989
1990    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
1991       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
1992        bts2rd = fat_fd->fat_file_size;
1993    else
1994        bts2rd = fs_info->fat.vol.bpc;
1995
1996    while ((ret = fat_file_read(&fs_info->fat, fat_fd, j * bts2rd, bts2rd,
1997                                  fs_info->cl_buf)) != FAT_EOF)
1998    {
1999        if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
2000            rtems_set_errno_and_return_minus_one( EIO );
2001
2002        assert(ret == bts2rd);
2003
2004        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
2005        {
2006            char* entry = (char*) fs_info->cl_buf + i;
2007
2008            /* if this and all rest entries are empty - return not-found */
2009            if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
2010                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
2011                return MSDOS_NAME_NOT_FOUND_ERR;
2012
2013            /* if this entry is empty - skip it */
2014            if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
2015                MSDOS_THIS_DIR_ENTRY_EMPTY)
2016                continue;
2017
2018            /* if get a non-empty entry - compare clusters num */
2019            if (MSDOS_EXTRACT_CLUSTER_NUM(entry) == cl4find)
2020            {
2021                /* on success fill aux structure and copy all 32 bytes */
2022                rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM, j * bts2rd,
2023                                    &dir_pos->sname.cln);
2024                if (rc != RC_OK)
2025                    return rc;
2026
2027                dir_pos->sname.ofs = i;
2028                dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
2029                dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
2030
2031                memcpy(dir_entry, entry,
2032                       MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
2033                return RC_OK;
2034            }
2035        }
2036        j++;
2037    }
2038    return MSDOS_NAME_NOT_FOUND_ERR;
2039}
2040
2041int
2042msdos_sync(rtems_libio_t *iop)
2043{
2044    int                rc = RC_OK;
2045    rtems_status_code  sc = RTEMS_SUCCESSFUL;
2046    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
2047
2048    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
2049                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
2050    if (sc != RTEMS_SUCCESSFUL)
2051        rtems_set_errno_and_return_minus_one(EIO);
2052
2053    rc = fat_sync(&fs_info->fat);
2054
2055    rtems_semaphore_release(fs_info->vol_sema);
2056    return rc;
2057}
Note: See TracBrowser for help on using the repository browser.