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

Last change on this file since ef0fe8e was ef0fe8e, checked in by Sebastian Huber <sebastian.huber@…>, on 12/02/20 at 12:18:42

dosfs: Fix Doxygen group placement

Update #3706.

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