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

4.11
Last change on this file since 5ed41a6 was 5ed41a6, checked in by Sebastian Huber <sebastian.huber@…>, on 03/14/17 at 10:41:18

dosfs: Fix msdos_add_file()

Make sure that long file names work accross cluster boundaries.

Close #2929.

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