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

4.11
Last change on this file since 004a63e was 004a63e, checked in by Christian Mauderer <Christian.Mauderer@…>, on 11/28/17 at 15:42:00

dosfs: Fix files with same name as volume name.

Take care that a file in the root directory with the same name as the
volume name can be found.

Close #3257.

  • Property mode set to 100644
File size: 65.0 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_LENGHT;
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_LENGHT;
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_LENGHT;
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                 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
1290static void
1291msdos_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
1302static int
1303msdos_find_file_in_directory (
1304    const uint8_t                        *filename_converted,
1305    const size_t                          name_len_for_compare,
1306    const size_t                          name_len_for_save,
1307    const msdos_name_type_t               name_type,
1308    msdos_fs_info_t                      *fs_info,
1309    fat_file_fd_t                        *fat_fd,
1310    const uint32_t                        bts2rd,
1311    const bool                            create_node,
1312    const unsigned int                    lfn_entries,
1313    char                                 *name_dir_entry,
1314    fat_dir_pos_t                        *dir_pos,
1315    uint32_t                             *empty_file_offset,
1316    uint32_t                             *empty_entry_count)
1317{
1318    int               rc                = RC_OK;
1319    ssize_t           bytes_read;
1320    uint32_t          dir_entry;
1321    fat_pos_t         lfn_start;
1322    uint8_t           lfn_checksum      = 0;
1323    bool              entry_matched;
1324    bool              empty_space_found = false;
1325    uint32_t          entries_per_block = bts2rd / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1326    int               lfn_entry         = 0;
1327    uint8_t           entry_utf8_normalized[MSDOS_LFN_ENTRY_SIZE_UTF8];
1328    size_t            bytes_in_entry;
1329    bool              filename_matched  = false;
1330    ssize_t           name_len_remaining;
1331    rtems_dosfs_convert_control *converter = fs_info->converter;
1332    uint32_t          dir_offset = 0;
1333
1334    /*
1335     * Scan the directory seeing if the file is present. While
1336     * doing this see if a suitable location can be found to
1337     * create the entry if the name is not found.
1338     */
1339
1340    msdos_prepare_for_next_entry(&lfn_start, &entry_matched,
1341                                 &name_len_remaining,
1342                                 name_len_for_compare);
1343
1344    while (   (bytes_read = fat_file_read (&fs_info->fat, fat_fd, (dir_offset * bts2rd),
1345                                             bts2rd, fs_info->cl_buf)) != FAT_EOF
1346           && rc == RC_OK)
1347    {
1348        bool remainder_empty = false;
1349#if MSDOS_FIND_PRINT
1350        printf ("MSFS:[2] dir_offset:%li\n", dir_offset);
1351#endif
1352
1353        if (bytes_read < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
1354            rtems_set_errno_and_return_minus_one(EIO);
1355
1356        assert(bytes_read == bts2rd);
1357
1358        /* have to look at the DIR_NAME as "raw" 8-bit data */
1359        for (dir_entry = 0;
1360             dir_entry < bts2rd && rc == RC_OK && (! filename_matched);
1361             dir_entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
1362        {
1363            char* entry = (char*) fs_info->cl_buf + dir_entry;
1364
1365            /*
1366             * See if the entry is empty or the remainder of the directory is
1367             * empty ? Localize to make the code read better.
1368             */
1369            bool entry_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
1370                                MSDOS_THIS_DIR_ENTRY_EMPTY);
1371            remainder_empty = (*MSDOS_DIR_ENTRY_TYPE(entry) ==
1372                               MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY);
1373#if MSDOS_FIND_PRINT
1374            printf ("MSFS:[3] re:%i ee:%i do:%li de:%li(%ld)\n",
1375                    remainder_empty, entry_empty, dir_offset,
1376                    dir_entry, (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE));
1377#endif
1378            /*
1379             * Remember where the we are, ie the start, so we can come back
1380             * to here and write the long file name if this is the start of
1381             * a series of empty entries. If empty_entry_count is 0 then
1382             * we are currently not inside an empty series of entries. It
1383             * is a count of empty entries.
1384             */
1385            if (*empty_entry_count == 0)
1386            {
1387                *empty_file_offset = dir_offset * bts2rd + dir_entry;
1388            }
1389
1390            if (remainder_empty)
1391            {
1392#if MSDOS_FIND_PRINT
1393                printf ("MSFS:[3.1] cn:%i esf:%i\n", create_node, empty_space_found);
1394#endif
1395                /*
1396                 * If just looking and there is no more entries in the
1397                 * directory - return name-not-found
1398                 */
1399                if (!create_node)
1400                    rc = MSDOS_NAME_NOT_FOUND_ERR;
1401
1402                /*
1403                 * Lets go and write the directory entries. If we have not found
1404                 * any available space add the remaining number of entries to any that
1405                 * we may have already found that are just before this entry. If more
1406                 * are needed FAT_EOF is returned by the read and we extend the file.
1407                 */
1408                if (   !empty_space_found
1409                    && rc == RC_OK )
1410                {
1411                    *empty_entry_count +=
1412                    entries_per_block - (dir_entry / MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1413                    empty_space_found = true;
1414#if MSDOS_FIND_PRINT
1415                    printf ( "MSFS:[3.2] esf:%i esc%"PRIu32"\n", empty_space_found, *empty_entry_count );
1416#endif
1417                }
1418                break;
1419            }
1420            else if (entry_empty)
1421            {
1422                if (create_node)
1423                {
1424                    /*
1425                     * Remainder is not empty so is this entry empty ?
1426                     */
1427                    (*empty_entry_count)++;
1428
1429                    if (*empty_entry_count == (lfn_entries + 1))
1430                        empty_space_found = true;
1431                }
1432#if MSDOS_FIND_PRINT
1433                printf ("MSFS:[4.1] esc:%li esf:%i\n",
1434                        *empty_entry_count, empty_space_found);
1435#endif
1436                msdos_prepare_for_next_entry(&lfn_start, &entry_matched,
1437                                             &name_len_remaining,
1438                                             name_len_for_compare);
1439            }
1440            else
1441            {
1442                /*
1443                 * A valid entry so handle it.
1444                 *
1445                 * If empty space has not been found we need to start the
1446                 * count again.
1447                 */
1448                if (create_node && !empty_space_found)
1449                {
1450                    *empty_file_offset = 0;
1451                    *empty_entry_count = 0;
1452                }
1453
1454                /*
1455                 * Check the attribute to see if the entry is for a long
1456                 * file name.
1457                 */
1458                if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_LFN_MASK) ==
1459                    MSDOS_ATTR_LFN)
1460                {
1461                    bool is_first_lfn_entry =
1462                        (lfn_start.cln == FAT_FILE_SHORT_NAME);
1463
1464/*                    int   o;*/
1465#if MSDOS_FIND_PRINT
1466                    printf ("MSFS:[4.2] lfn:%c entry:%i checksum:%i\n",
1467                            lfn_start.cln == FAT_FILE_SHORT_NAME ? 'f' : 't',
1468                            *MSDOS_DIR_ENTRY_TYPE(entry) & MSDOS_LAST_LONG_ENTRY_MASK,
1469                            *MSDOS_DIR_LFN_CHECKSUM(entry));
1470#endif
1471                    /*
1472                     * If we are not already processing a LFN see if this is
1473                     * the first entry of a LFN ?
1474                     */
1475                    if (is_first_lfn_entry)
1476                    {
1477                        entry_matched = false;
1478
1479                        /*
1480                         * The first entry must have the last long entry
1481                         * flag set.
1482                         */
1483                        if ((*MSDOS_DIR_ENTRY_TYPE(entry) &
1484                             MSDOS_LAST_LONG_ENTRY) == 0)
1485                            continue;
1486
1487                        lfn_start.cln = dir_offset;
1488                        lfn_start.ofs = dir_entry;
1489                        lfn_entry = (*MSDOS_DIR_ENTRY_TYPE(entry)
1490                            & MSDOS_LAST_LONG_ENTRY_MASK);
1491                        lfn_checksum = *MSDOS_DIR_LFN_CHECKSUM(entry);
1492
1493#if MSDOS_FIND_PRINT
1494                        printf ("MSFS:[4.3] lfn_checksum:%i\n",
1495                                lfn_checksum);
1496#endif
1497                    }
1498
1499                    /*
1500                     * If the entry number or the check sum do not match
1501                     * forget this series of long directory entries. These
1502                     * could be orphaned entries depending on the history
1503                     * of the disk.
1504                     */
1505                    if ((lfn_entry != (*MSDOS_DIR_ENTRY_TYPE(entry) &
1506                                       MSDOS_LAST_LONG_ENTRY_MASK)) ||
1507                        (lfn_checksum != *MSDOS_DIR_LFN_CHECKSUM(entry)))
1508                    {
1509#if MSDOS_FIND_PRINT
1510                        printf ("MSFS:[4.4] no match\n");
1511#endif
1512                        msdos_prepare_for_next_entry(&lfn_start,
1513                                                     &entry_matched,
1514                                                     &name_len_remaining,
1515                                                     name_len_for_compare);
1516                        continue;
1517                    }
1518#if MSDOS_FIND_PRINT
1519                    printf ("MSFS:[5] lfne:%i\n", lfn_entry);
1520#endif
1521                    lfn_entry--;
1522
1523                    bytes_in_entry = msdos_long_entry_to_utf8_name (
1524                        converter,
1525                        entry,
1526                        is_first_lfn_entry,
1527                        &entry_utf8_normalized[0],
1528                        sizeof (entry_utf8_normalized));
1529                    if (bytes_in_entry > 0) {
1530                        name_len_remaining = msdos_compare_entry_against_filename (
1531                            converter,
1532                            &entry_utf8_normalized[0],
1533                            bytes_in_entry,
1534                            &filename_converted[0],
1535                            name_len_remaining,
1536                            &entry_matched);
1537
1538                        if (name_len_remaining < 0 || !entry_matched) {
1539                            msdos_prepare_for_next_entry(&lfn_start,
1540                                                         &entry_matched,
1541                                                         &name_len_remaining,
1542                                                         name_len_for_compare);
1543                        }
1544                    } else {
1545                        msdos_prepare_for_next_entry(&lfn_start,
1546                                                     &entry_matched,
1547                                                     &name_len_remaining,
1548                                                     name_len_for_compare);
1549                    }
1550                }
1551                else
1552                {
1553#if MSDOS_FIND_PRINT
1554                    printf ("MSFS:[9.1] SFN entry, entry_matched:%i\n", entry_matched);
1555#endif
1556                    /*
1557                     * SFN entry found.
1558                     *
1559                     * If a LFN has been found and it matched check the
1560                     * entries have all been found and the checksum is
1561                     * correct. If this is the case return the short file
1562                     * name entry.
1563                     */
1564                    if (entry_matched)
1565                    {
1566                        if (lfn_entry ||
1567                            lfn_checksum != msdos_lfn_checksum(entry))
1568                            entry_matched = false;
1569                        else if (name_len_remaining == 0) {
1570                            filename_matched = true;
1571                            rc = msdos_on_entry_found (
1572                                fs_info,
1573                                fat_fd,
1574                                bts2rd,
1575                                name_dir_entry,
1576                                entry,
1577                                dir_pos,
1578                                dir_offset,
1579                                dir_entry,
1580                                &lfn_start
1581                            );
1582                        }
1583
1584#if MSDOS_FIND_PRINT
1585                        printf ("MSFS:[9.2] checksum, entry_matched:%i, lfn_entry:%i, lfn_checksum:%02x/%02x\n",
1586                                entry_matched, lfn_entry, lfn_checksum, msdos_lfn_checksum(entry));
1587#endif
1588                    } else if ((*MSDOS_DIR_ATTR(entry) & MSDOS_ATTR_VOLUME_ID)
1589                               == 0) {
1590                        bytes_in_entry = MSDOS_SHORT_NAME_LEN + 1;
1591                        bytes_in_entry = msdos_short_entry_to_utf8_name (
1592                            converter,
1593                            MSDOS_DIR_NAME (entry),
1594                            &entry_utf8_normalized[0],
1595                            bytes_in_entry);
1596                        if (bytes_in_entry > 0) {
1597                            name_len_remaining = msdos_compare_entry_against_filename (
1598                                converter,
1599                                &entry_utf8_normalized[0],
1600                                bytes_in_entry,
1601                                &filename_converted[0],
1602                                name_len_for_compare,
1603                                &entry_matched);
1604                            if (entry_matched && name_len_remaining == 0) {
1605                                filename_matched = true;
1606                                rc = msdos_on_entry_found (
1607                                    fs_info,
1608                                    fat_fd,
1609                                    bts2rd,
1610                                    name_dir_entry,
1611                                    entry,
1612                                    dir_pos,
1613                                    dir_offset,
1614                                    dir_entry,
1615                                    &lfn_start
1616                                );
1617                            }
1618                            if (rc == RC_OK && !filename_matched) {
1619                                msdos_prepare_for_next_entry(&lfn_start,
1620                                                             &entry_matched,
1621                                                             &name_len_remaining,
1622                                                             name_len_for_compare);
1623                            }
1624                        } else {
1625                          msdos_prepare_for_next_entry(&lfn_start,
1626                                                       &entry_matched,
1627                                                       &name_len_remaining,
1628                                                       name_len_for_compare);
1629                        }
1630                    }
1631                }
1632            }
1633        }
1634
1635        if (filename_matched || remainder_empty)
1636            break;
1637
1638        dir_offset++;
1639    }
1640    if ( ! filename_matched ) {
1641        /*
1642         * If we are not to create the entry return a not found error.
1643         */
1644        if (!create_node)
1645            rc = MSDOS_NAME_NOT_FOUND_ERR;
1646
1647#if MSDOS_FIND_PRINT
1648        printf ( "MSFS:[8.1] WRITE do:%"PRIu32" esc:%"PRIu32" efo:%"PRIu32"\n",
1649                 dir_offset, *empty_entry_count, *empty_file_offset );
1650#endif
1651    }
1652
1653    return rc;
1654}
1655
1656static int
1657msdos_get_pos(
1658    msdos_fs_info_t *fs_info,
1659    fat_file_fd_t   *fat_fd,
1660    uint32_t         bts2rd,
1661    uint32_t         file_offset,
1662    fat_pos_t       *pos
1663)
1664{
1665    pos->ofs = file_offset & (bts2rd - 1);
1666    return fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM,
1667                          file_offset, &pos->cln);
1668}
1669
1670static int
1671msdos_add_file (
1672    const char                           *name_converted,
1673    const msdos_name_type_t               name_type,
1674    msdos_fs_info_t                      *fs_info,
1675    fat_file_fd_t                        *fat_fd,
1676    const uint32_t                        bts2rd,
1677    const unsigned int                    lfn_entries,
1678    const char                           *name_dir_entry,
1679    fat_dir_pos_t                        *dir_pos,
1680    uint32_t                              empty_file_offset,
1681    const uint32_t                        empty_entry_count
1682)
1683{
1684    int              ret;
1685    ssize_t          bytes_written;
1686    uint8_t          lfn_checksum;
1687    int              lfn_entry;
1688    uint8_t         *entry;
1689    uint32_t         short_file_offset;
1690    uint32_t         length;
1691
1692    /*
1693     * If there is not enough space available then extend the file.
1694     */
1695    if (empty_entry_count < lfn_entries + 1)
1696    {
1697        uint32_t unused;
1698
1699        empty_file_offset = fat_fd->fat_file_size -
1700            empty_entry_count * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1701
1702        ret = fat_file_extend(&fs_info->fat,
1703                              fat_fd,
1704                              true,
1705                              fat_fd->fat_file_size + fs_info->fat.vol.bpc,
1706                              &unused);
1707        if (ret != RC_OK)
1708            return ret;
1709    }
1710
1711    if (name_type == MSDOS_NAME_LONG)
1712    {
1713        uint32_t slot;
1714
1715        /*
1716         * If a long file name calculate the checksum of the short file name
1717         * data to place in each long file name entry. First set the short
1718         * file name to the slot of the SFN entry. This will mean no clashes
1719         * in this directory.
1720         */
1721        slot = (empty_file_offset /
1722            MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE) + lfn_entries + 1;
1723        msdos_short_name_hex(MSDOS_DIR_NAME(name_dir_entry), slot);
1724
1725        lfn_checksum = msdos_lfn_checksum(name_dir_entry);
1726
1727        short_file_offset = empty_file_offset + lfn_entries
1728            * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1729
1730        /* Get position of first long file name entry */
1731        ret = msdos_get_pos(fs_info, fat_fd, bts2rd, empty_file_offset,
1732                            &dir_pos->lname);
1733        if (ret != RC_OK)
1734            return ret;
1735    } else {
1736        lfn_checksum = 0;
1737        short_file_offset = empty_file_offset;
1738        dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
1739        dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
1740    }
1741
1742    /* Get position of short file name entry */
1743    ret = msdos_get_pos(fs_info, fat_fd, bts2rd, short_file_offset,
1744                        &dir_pos->sname);
1745
1746    /*
1747     * Handle the entry writes.
1748     */
1749    entry = fs_info->cl_buf;
1750
1751#if MSDOS_FIND_PRINT
1752    printf ("MSFS:[9] read_cluster:%d efo:%ld ese:%ld\n",
1753            read_cluster, empty_file_offset, empty_space_entry);
1754#endif
1755
1756    /* Long file name entries */
1757    for (lfn_entry = 0; lfn_entry < lfn_entries; ++lfn_entry) {
1758        uint8_t       *p;
1759        const uint8_t *n;
1760        int            i;
1761        uint8_t        fill = 0;
1762
1763        /*
1764         * Clear the entry before loading the data.
1765         */
1766        memset (entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1767
1768        *MSDOS_DIR_LFN_CHECKSUM(entry) = lfn_checksum;
1769
1770        p = entry + 1;
1771        n = (const uint8_t *) name_converted +
1772            (lfn_entries - lfn_entry - 1) * MSDOS_LFN_ENTRY_SIZE;
1773
1774#if MSDOS_FIND_PRINT
1775        printf ("MSFS:[11] ");
1776#endif
1777        for (i = 0; i < MSDOS_LFN_LEN_PER_ENTRY; ++i)
1778        {
1779            if (*n != 0 || *(n + 1) != 0)
1780            {
1781                *p = *n;
1782                *(p + 1) = *(n + 1);
1783                n += MSDOS_NAME_LFN_BYTES_PER_CHAR;
1784            }
1785            else
1786            {
1787                p [0] = fill;
1788                p [1] = fill;
1789                fill = 0xff;
1790            }
1791#if MSDOS_FIND_PRINT
1792            printf ( "'%c''%c'", *p, *(p+1) );
1793#endif
1794
1795            switch (i)
1796            {
1797                case 4:
1798                    p += 5;
1799                    break;
1800                case 10:
1801                    p += 4;
1802                    break;
1803                default:
1804                    p += 2;
1805                    break;
1806            }
1807        }
1808#if MSDOS_FIND_PRINT
1809        printf ( "\n" );
1810#endif
1811        *MSDOS_DIR_ENTRY_TYPE(entry) = lfn_entries - lfn_entry;
1812        if (lfn_entry == 0)
1813            *MSDOS_DIR_ENTRY_TYPE(entry) |= MSDOS_LAST_LONG_ENTRY;
1814        *MSDOS_DIR_ATTR(entry) |= MSDOS_ATTR_LFN;
1815
1816        entry += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1817    }
1818
1819    /* Short file name entry */
1820    memcpy(entry, name_dir_entry, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
1821
1822    length = (lfn_entries + 1) * MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE;
1823    bytes_written = fat_file_write(&fs_info->fat, fat_fd,
1824                                   empty_file_offset,
1825                                   length, fs_info->cl_buf);
1826    if (bytes_written == (ssize_t) length)
1827        return 0;
1828    else if (bytes_written == -1)
1829        return -1;
1830    else
1831        rtems_set_errno_and_return_minus_one(EIO);
1832}
1833
1834int
1835msdos_find_name_in_fat_file (
1836    rtems_filesystem_mount_table_entry_t *mt_entry,
1837    fat_file_fd_t                        *fat_fd,
1838    bool                                  create_node,
1839    const uint8_t                        *name_utf8,
1840    int                                   name_utf8_len,
1841    msdos_name_type_t                     name_type,
1842    fat_dir_pos_t                        *dir_pos,
1843    char                                 *name_dir_entry)
1844{
1845    int                                retval                     = 0;
1846    msdos_fs_info_t                   *fs_info                    = mt_entry->fs_info;
1847    ssize_t                            name_len_for_save;
1848    ssize_t                            name_len_for_compare;
1849    uint32_t                           bts2rd                     = 0;
1850    uint32_t                           empty_file_offset          = 0;
1851    uint32_t                           empty_entry_count          = 0;
1852    unsigned int                       lfn_entries;
1853    rtems_dosfs_convert_control       *converter = fs_info->converter;
1854    void                              *buffer = converter->buffer.data;
1855    size_t                             buffer_size = converter->buffer.size;
1856
1857    assert(name_utf8_len > 0);
1858
1859    fat_dir_pos_init(dir_pos);
1860
1861
1862
1863    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
1864        (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
1865        bts2rd = fat_fd->fat_file_size;
1866    else
1867        bts2rd = fs_info->fat.vol.bpc;
1868
1869    switch ( name_type ) {
1870        case MSDOS_NAME_SHORT:
1871            name_len_for_compare = msdos_filename_utf8_to_short_name_for_compare (
1872                converter,
1873                name_utf8,
1874                name_utf8_len,
1875                buffer,
1876                MSDOS_SHORT_NAME_LEN);
1877            if (name_len_for_compare > 0) {
1878                lfn_entries = 0;
1879            }
1880            else
1881                retval = -1;
1882        break;
1883        case MSDOS_NAME_LONG:
1884            name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
1885                converter,
1886                name_utf8,
1887                name_utf8_len,
1888                buffer,
1889                buffer_size);
1890            if (name_len_for_save > 0) {
1891                lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
1892                    / MSDOS_LFN_ENTRY_SIZE;
1893                name_len_for_compare = msdos_filename_utf8_to_long_name_for_compare (
1894                  converter,
1895                  name_utf8,
1896                  name_utf8_len,
1897                  buffer,
1898                  buffer_size);
1899                if (0 >= name_len_for_compare) {
1900                    retval = -1;
1901                }
1902            }
1903            else
1904                retval = -1;
1905        break;
1906        default:
1907            errno = EINVAL;
1908            retval = -1;
1909        break;
1910    }
1911    if (retval == RC_OK) {
1912      /* See if the file/directory does already exist */
1913      retval = msdos_find_file_in_directory (
1914          buffer,
1915          name_len_for_compare,
1916          name_len_for_save,
1917          name_type,
1918          fs_info,
1919          fat_fd,
1920          bts2rd,
1921          create_node,
1922          lfn_entries,
1923          name_dir_entry,
1924          dir_pos,
1925          &empty_file_offset,
1926          &empty_entry_count);
1927    }
1928    /* Create a non-existing file/directory if requested */
1929    if (   retval == RC_OK
1930        && create_node) {
1931        switch (name_type) {
1932          case MSDOS_NAME_SHORT:
1933              name_len_for_save = msdos_filename_utf8_to_short_name_for_save (
1934                  converter,
1935                  name_utf8,
1936                  name_utf8_len,
1937                  buffer,
1938                  MSDOS_SHORT_NAME_LEN);
1939              if (name_len_for_save > 0 ) {
1940                  lfn_entries = 0;
1941              }
1942              else
1943                  retval = -1;
1944          break;
1945          case MSDOS_NAME_LONG:
1946              name_len_for_save = msdos_filename_utf8_to_long_name_for_save (
1947                  converter,
1948                  name_utf8,
1949                  name_utf8_len,
1950                  buffer,
1951                  buffer_size);
1952              if (name_len_for_save > 0) {
1953                  lfn_entries = (name_len_for_save + MSDOS_LFN_ENTRY_SIZE - 1)
1954                    / MSDOS_LFN_ENTRY_SIZE;
1955              }
1956              else
1957                  retval = -1;
1958          break;
1959          default:
1960              errno = EINVAL;
1961              retval = -1;
1962          break;
1963        }
1964
1965        if (retval == RC_OK)
1966            retval = msdos_add_file (
1967                buffer,
1968                name_type,
1969                fs_info,
1970                fat_fd,
1971                bts2rd,
1972                lfn_entries,
1973                name_dir_entry,
1974                dir_pos,
1975                empty_file_offset,
1976                empty_entry_count
1977            );
1978    }
1979
1980    return retval;
1981}
1982
1983
1984/* msdos_find_node_by_cluster_num_in_fat_file --
1985 *     Find node with specified number of cluster in fat-file.
1986 *
1987 * Note, not updated in the LFN change because it is only used
1988 *       for . and .. entries and these are always short.
1989 *
1990 * PARAMETERS:
1991 *     mt_entry  - mount table entry
1992 *     fat_fd    - fat-file descriptor
1993 *     cl4find   - number of cluster to find
1994 *     paux      - identify a node location on the disk -
1995 *                 cluster num and offset inside the cluster
1996 *     dir_entry - placeholder for found node
1997 *
1998 * RETURNS:
1999 *     RC_OK on success, or error code if error occured
2000 *
2001 */
2002int msdos_find_node_by_cluster_num_in_fat_file(
2003    rtems_filesystem_mount_table_entry_t *mt_entry,
2004    fat_file_fd_t                        *fat_fd,
2005    uint32_t                              cl4find,
2006    fat_dir_pos_t                        *dir_pos,
2007    char                                 *dir_entry
2008    )
2009{
2010    int              rc = RC_OK;
2011    ssize_t          ret = 0;
2012    msdos_fs_info_t *fs_info = mt_entry->fs_info;
2013    uint32_t         bts2rd = 0;
2014    uint32_t         i = 0, j = 0;
2015
2016    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
2017       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
2018        bts2rd = fat_fd->fat_file_size;
2019    else
2020        bts2rd = fs_info->fat.vol.bpc;
2021
2022    while ((ret = fat_file_read(&fs_info->fat, fat_fd, j * bts2rd, bts2rd,
2023                                  fs_info->cl_buf)) != FAT_EOF)
2024    {
2025        if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
2026            rtems_set_errno_and_return_minus_one( EIO );
2027
2028        assert(ret == bts2rd);
2029
2030        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
2031        {
2032            char* entry = (char*) fs_info->cl_buf + i;
2033
2034            /* if this and all rest entries are empty - return not-found */
2035            if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
2036                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
2037                return MSDOS_NAME_NOT_FOUND_ERR;
2038
2039            /* if this entry is empty - skip it */
2040            if ((*MSDOS_DIR_ENTRY_TYPE(entry)) ==
2041                MSDOS_THIS_DIR_ENTRY_EMPTY)
2042                continue;
2043
2044            /* if get a non-empty entry - compare clusters num */
2045            if (MSDOS_EXTRACT_CLUSTER_NUM(entry) == cl4find)
2046            {
2047                /* on success fill aux structure and copy all 32 bytes */
2048                rc = fat_file_ioctl(&fs_info->fat, fat_fd, F_CLU_NUM, j * bts2rd,
2049                                    &dir_pos->sname.cln);
2050                if (rc != RC_OK)
2051                    return rc;
2052
2053                dir_pos->sname.ofs = i;
2054                dir_pos->lname.cln = FAT_FILE_SHORT_NAME;
2055                dir_pos->lname.ofs = FAT_FILE_SHORT_NAME;
2056
2057                memcpy(dir_entry, entry,
2058                       MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
2059                return RC_OK;
2060            }
2061        }
2062        j++;
2063    }
2064    return MSDOS_NAME_NOT_FOUND_ERR;
2065}
2066
2067int
2068msdos_sync(rtems_libio_t *iop)
2069{
2070    int                rc = RC_OK;
2071    rtems_status_code  sc = RTEMS_SUCCESSFUL;
2072    msdos_fs_info_t   *fs_info = iop->pathinfo.mt_entry->fs_info;
2073
2074    sc = rtems_semaphore_obtain(fs_info->vol_sema, RTEMS_WAIT,
2075                                MSDOS_VOLUME_SEMAPHORE_TIMEOUT);
2076    if (sc != RTEMS_SUCCESSFUL)
2077        rtems_set_errno_and_return_minus_one(EIO);
2078
2079    rc = fat_sync(&fs_info->fat);
2080
2081    rtems_semaphore_release(fs_info->vol_sema);
2082    return rc;
2083}
Note: See TracBrowser for help on using the repository browser.