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

4.104.114.84.9
Last change on this file since 48d2477 was 48d2477, checked in by Ralf Corsepius <ralf.corsepius@…>, on Oct 17, 2005 at 9:30:38 AM

2005-10-17 Ralf Corsepius <ralf.corsepius@…>

  • libfs/src/dosfs/msdos_misc.c: Revert to vers. 1.9.
  • Property mode set to 100644
File size: 29.3 KB
Line 
1/*
2 *  Miscellaneous routines implementation for MSDOS filesystem
3 *
4 *  Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
5 *  Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
6 *
7 *  The license and distribution terms for this file may be
8 *  found in the file LICENSE in this distribution or at
9 *  http://www.rtems.com/license/LICENSE.
10 *
11 *  @(#) $Id$
12 */
13
14#if HAVE_CONFIG_H
15#include "config.h"
16#endif
17
18#include <stdlib.h>
19#include <sys/time.h>
20#include <unistd.h>
21#include <string.h>
22#include <assert.h>
23#include <rtems/libio_.h>
24
25#include "fat.h"
26#include "fat_fat_operations.h"
27#include "fat_file.h"
28
29#include "msdos.h"
30
31/* msdos_get_token --
32 *     Routine to get a token (name or separator) from the path.
33 *
34 * PARAMETERS:
35 *     path      - path to get token from
36 *     ret_token - returned token
37 *     token_len - length of returned token
38 *
39 * RETURNS:
40 *     token type, token and token length
41 *
42 */
43msdos_token_types_t
44msdos_get_token(const char *path, char *ret_token, int *token_len)
45{
46    int                 rc = RC_OK;
47    register int        i = 0;
48    msdos_token_types_t type = MSDOS_NAME;
49    char                token[MSDOS_NAME_MAX_WITH_DOT+1];
50    register char       c;
51
52    /*
53     *  Copy a name into token.  (Remember NULL is a token.)
54     */
55    c = path[i];
56    while ( (!msdos_is_separator(c)) && (i <= MSDOS_NAME_MAX_WITH_DOT) )
57    {
58        token[i] = c;
59        if ( i == MSDOS_NAME_MAX_WITH_DOT )
60            return MSDOS_INVALID_TOKEN;
61        if ( !msdos_is_valid_name_char(c) )
62            return MSDOS_INVALID_TOKEN;
63        c = path [++i];
64    }
65
66    /*
67     *  Copy a seperator into token.
68     */
69    if ( i == 0 )
70    {
71        token[i] = c;
72        if ( token[i] != '\0' )
73        {
74            i++;
75            type = MSDOS_CURRENT_DIR;
76        }
77        else
78            type = MSDOS_NO_MORE_PATH;
79    }
80    else if (token[ i-1 ] != '\0')
81        token[i] = '\0';
82
83    /*
84     *  Set token_len to the number of characters copied.
85     */
86    *token_len = i;
87
88    /*
89     *  If we copied something that was not a seperator see if
90     *  it was a special name.
91     */
92    if ( type == MSDOS_NAME )
93    {
94        if ( strcmp( token, "..") == 0 )
95        {
96            strcpy(ret_token, MSDOS_DOTDOT_NAME);
97            type = MSDOS_UP_DIR;
98            return type;
99        }
100
101        if ( strcmp( token, "." ) == 0 )
102        {
103            strcpy(ret_token, MSDOS_DOT_NAME);
104            type = MSDOS_CURRENT_DIR;
105            return type;
106        }
107
108        rc = msdos_filename_unix2dos(token, *token_len, ret_token);
109        if ( rc != RC_OK )
110            return MSDOS_INVALID_TOKEN;
111    }
112    ret_token[MSDOS_NAME_MAX] = '\0';
113    return type;
114}
115
116
117/* msdos_find_name --
118 *     Find the node which correspondes to the name, open fat-file which
119 *     correspondes to the found node and close fat-file which correspondes
120 *     to the node we searched in.
121 *
122 * PARAMETERS:
123 *     parent_loc - parent node description
124 *     name       - name to find
125 *
126 * RETURNS:
127 *     RC_OK and updated 'parent_loc' on success, or -1 if error
128 *     occured (errno set apropriately)
129 *
130 */
131int
132msdos_find_name(
133    rtems_filesystem_location_info_t *parent_loc,
134    char                             *name
135    )
136{
137    int              rc = RC_OK;
138    msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
139    fat_file_fd_t   *fat_fd = NULL;
140    fat_auxiliary_t  aux;
141    unsigned short   time_val = 0;
142    unsigned short   date = 0;
143    char             node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
144
145    memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
146
147    /*
148     * find the node which correspondes to the name in the directory pointed by
149     * 'parent_loc'
150     */
151    rc = msdos_get_name_node(parent_loc, name, &aux, node_entry);
152    if (rc != RC_OK)
153        return rc;
154
155    /* open fat-file corresponded to the found node */
156    rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
157    if (rc != RC_OK)
158        return rc;
159
160    /*
161     * I don't like this if, but: we should do it , or should write new file
162     * size and first cluster num to the disk after each write operation
163     * (even if one byte is written  - that is TOO non-optimize) because
164     * otherwise real values of these fields stored in fat-file descriptor
165     * may be accidentely rewritten with wrong values stored on the disk
166     */
167    if (fat_fd->links_num == 1)
168    {
169        fat_fd->info_cln = aux.cln;
170        fat_fd->info_ofs = aux.ofs;
171        fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
172        fat_fd->first_char = *MSDOS_DIR_NAME(node_entry);
173
174        time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
175        date = *MSDOS_DIR_WRITE_DATE(node_entry);
176
177        fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date));
178
179        if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
180        {
181            fat_fd->fat_file_type = FAT_DIRECTORY;
182            fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
183
184            rc = fat_file_size(parent_loc->mt_entry, fat_fd);
185            if (rc != RC_OK)
186            {
187                fat_file_close(parent_loc->mt_entry, fat_fd);
188                return rc;
189            }
190        }
191        else
192        {
193            fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
194            fat_fd->fat_file_type = FAT_FILE;
195            fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
196        }
197
198        /* these data is not actual for zero-length fat-file */
199        fat_fd->map.file_cln = 0;
200        fat_fd->map.disk_cln = fat_fd->cln;
201
202        if ((fat_fd->fat_file_size != 0) &&
203            (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
204        {
205            fat_fd->map.last_cln = fat_fd->cln;
206        }
207        else
208        {
209            fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
210        }
211    }
212
213    /* close fat-file corresponded to the node we searched in */
214    rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access);
215    if (rc != RC_OK)
216    {
217        fat_file_close(parent_loc->mt_entry, fat_fd);
218        return rc;
219    }
220
221    /* update node_info_ptr field */
222    parent_loc->node_access = fat_fd;
223
224    return rc;
225}
226
227/* msdos_get_name_node --
228 *     This routine is used in two ways: for a new mode creation (a) or for
229 *     search the node which correspondes to the name parameter (b).
230 *     In case (a) 'name' should be set up to NULL and 'name_dir_entry' should
231 *     point to initialized 32 bytes structure described a new node.
232 *     In case (b) 'name' should contain a valid string.
233 *
234 *     (a): reading fat-file which correspondes to directory we are going to
235 *          create node in. If free slot is found write contents of
236 *          'name_dir_entry' into it. If reach end of fat-file and no free
237 *          slot found, write 32 bytes to the end of fat-file.
238 *
239 *     (b): reading fat-file which correspondes to directory and trying to
240 *          find slot with the name field == 'name' parameter
241 *
242 *
243 * PARAMETERS:
244 *     parent_loc     - node description to create node in or to find name in
245 *     name           - NULL or name to find
246 *     paux           - identify a node location on the disk -
247 *                      cluster num and offset inside the cluster
248 *     name_dir_entry - node to create/placeholder for found node (IN/OUT)
249 *
250 * RETURNS:
251 *     RC_OK, filled aux_struct_ptr and name_dir_entry on success, or -1 if
252 *     error occured (errno set apropriately)
253 *
254 */
255msdos_status_t
256msdos_get_name_node(
257    rtems_filesystem_location_info_t *parent_loc,
258    char                             *name,
259    fat_auxiliary_t                  *paux,
260    char                             *name_dir_entry
261    )
262{
263    msdos_status_t   rc = RC_OK;
264    ssize_t          ret = 0;
265    msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
266    fat_file_fd_t   *fat_fd = parent_loc->node_access;
267    uint32_t         dotdot_cln = 0;
268
269    /* find name in fat-file which correspondes to the directory */
270    rc = msdos_find_name_in_fat_file(parent_loc->mt_entry, fat_fd, name, paux,
271                                     name_dir_entry);
272    if ((rc != RC_OK) && (rc != MSDOS_NAME_NOT_FOUND_ERR))
273        return rc;
274
275    /* if we search for valid name and name not found -> return */
276    if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name != NULL))
277        return rc;
278
279    /*
280     * if we try to create new entry and the directory is not big enough
281     * currently - try to enlarge directory
282     */
283    if ((rc == MSDOS_NAME_NOT_FOUND_ERR) && (name == NULL))
284    {
285        ret = fat_file_write(parent_loc->mt_entry, fat_fd,
286                             fat_fd->fat_file_size,
287                             MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
288                             (uint8_t *)name_dir_entry);
289        if (ret == -1)
290            return -1;
291
292        /* on success directory is enlarged by a new cluster */
293        fat_fd->fat_file_size += fs_info->fat.vol.bpc;
294
295        /* get cluster num where a new node located */
296        rc = fat_file_ioctl(parent_loc->mt_entry, fat_fd, F_CLU_NUM,
297                            fat_fd->fat_file_size - 1, &paux->cln);
298
299        if (rc != RC_OK)
300            return rc;
301
302        /*
303         * if new cluster allocated succesfully then new node is at very
304         * beginning of the cluster (offset is computed in bytes)
305         */
306        paux->ofs = 0;
307        return RC_OK;
308    }
309
310    /*
311     * if we have deal with ".." - it is a special case :(((
312     *
313     * Really, we should return cluster num and offset not of ".." slot, but
314     * slot which correspondes to real directory name.
315     */
316    if ((rc == RC_OK) && (name != NULL))
317    {
318        if (strncmp(name, MSDOS_DOTDOT_NAME, MSDOS_SHORT_NAME_LEN) == 0)
319        {
320            dotdot_cln = MSDOS_EXTRACT_CLUSTER_NUM((name_dir_entry));
321
322            /* are we right under root dir ? */
323            if (dotdot_cln == 0)
324            {
325                /*
326                 * we can relax about first_char field - it never should be
327                 * used for root dir
328                 */
329                paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
330                paux->ofs = 0;
331            }
332            else
333            {
334                rc = msdos_get_dotdot_dir_info_cluster_num_and_offset(
335                        parent_loc->mt_entry,
336                        dotdot_cln,
337                        paux,
338                        name_dir_entry
339                        );
340                if (rc != RC_OK)
341                    return rc;
342            }
343        }
344    }
345    return rc;
346}
347
348/*
349 * msdos_get_dotdot_dir_info_cluster_num_and_offset
350 *
351 * Unfortunately, in general, we cann't work here in fat-file ideologic
352 * (open fat_file "..", get ".." and ".", open "..", find an entry ...)
353 * because if we open
354 * fat-file ".." it may happend that we have two different fat-file
355 * descriptors ( for real name of directory and ".." name ) for a single
356 * file  ( cluster num of both pointers to the same cluster )
357 * But...we do it because we protected by semaphore
358 *
359 */
360
361/* msdos_get_dotdot_dir_info_cluster_num_and_offset --
362 *     Get cluster num and offset not of ".." slot, but slot which correspondes
363 *     to real directory name.
364 *
365 * PARAMETERS:
366 *     mt_entry       - mount table entry
367 *     cln            - data cluster num extracted drom ".." slot
368 *     paux           - identify a node location on the disk -
369 *                      number of cluster and offset inside the cluster
370 *     dir_entry      - placeholder for found node
371 *
372 * RETURNS:
373 *     RC_OK, filled 'paux' and 'dir_entry' on success, or -1 if error occured
374 *     (errno set apropriately)
375 *
376 */
377int
378msdos_get_dotdot_dir_info_cluster_num_and_offset(
379    rtems_filesystem_mount_table_entry_t *mt_entry,
380    uint32_t                              cln,
381    fat_auxiliary_t                      *paux,
382    char                                 *dir_entry
383    )
384{
385    int              rc = RC_OK;
386    msdos_fs_info_t *fs_info = mt_entry->fs_info;
387    fat_file_fd_t   *fat_fd = NULL;
388    char             dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
389    char             dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
390    uint32_t         cl4find = 0;
391
392    memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
393    memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
394
395    /*
396     * open fat-file corresponded to ".."
397     */
398    rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
399    if (rc != RC_OK)
400        return rc;
401
402    fat_fd->info_cln = paux->cln;
403    fat_fd->info_ofs = paux->ofs;
404    fat_fd->cln = cln;
405    fat_fd->fat_file_type = FAT_DIRECTORY;
406    fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
407
408    fat_fd->map.file_cln = 0;
409    fat_fd->map.disk_cln = fat_fd->cln;
410
411    rc = fat_file_size(mt_entry, fat_fd);
412    if (rc != RC_OK)
413    {
414        fat_file_close(mt_entry, fat_fd);
415        return rc;
416    }
417
418    /* find "." node in opened directory */
419    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux,
420                                     dot_node);
421
422    if (rc != RC_OK)
423    {
424        fat_file_close(mt_entry, fat_fd);
425        return rc;
426    }
427
428    /* find ".." node in opened directory */
429    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux,
430                                     dotdot_node);
431
432    if (rc != RC_OK)
433    {
434        fat_file_close(mt_entry, fat_fd);
435        return rc;
436    }
437
438    cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
439
440    /* close fat-file corresponded to ".." directory */
441    rc = fat_file_close(mt_entry, fat_fd);
442    if ( rc != RC_OK )
443        return rc;
444
445    if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
446    {
447        /*
448         * we handle root dir for all FAT types in the same way with the
449         * ordinary directories ( through fat_file_* calls )
450         */
451        paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
452        paux->ofs = 0;
453    }
454
455    /* open fat-file corresponded to second ".." */
456    rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
457    if (rc != RC_OK)
458        return rc;
459
460    fat_fd->info_cln = paux->cln;
461    fat_fd->info_ofs = paux->ofs;
462
463    if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
464        fat_fd->cln = fs_info->fat.vol.rdir_cl;
465    else
466        fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
467
468    fat_fd->fat_file_type = FAT_DIRECTORY;
469    fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
470
471    fat_fd->map.file_cln = 0;
472    fat_fd->map.disk_cln = fat_fd->cln;
473
474    rc = fat_file_size(mt_entry, fat_fd);
475    if (rc != RC_OK)
476    {
477        fat_file_close(mt_entry, fat_fd);
478        return rc;
479    }
480
481    /* in this directory find slot with specified cluster num */
482    rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
483                                                    paux, dir_entry);
484    if (rc != RC_OK)
485    {
486        fat_file_close(mt_entry, fat_fd);
487        return rc;
488    }
489    rc = fat_file_close(mt_entry, fat_fd);
490    return rc;
491}
492
493
494/* msdos_set_dir_wrt_time_and_date --
495 *     Write last write date and time for a file to the disk (to corresponded
496 *     32bytes node)
497 *
498 * PARAMETERS:
499 *     mt_entry - mount table entry
500 *     fat_fd   - fat-file descriptor
501 *
502 * RETURNS:
503 *     RC_OK on success, or -1 if error occured (errno set apropriately).
504 *
505 */
506int
507msdos_set_dir_wrt_time_and_date(
508    rtems_filesystem_mount_table_entry_t *mt_entry,
509    fat_file_fd_t                        *fat_fd
510    )
511{
512    ssize_t          ret1 = 0, ret2 = 0;
513    msdos_fs_info_t *fs_info = mt_entry->fs_info;
514    unsigned short   time_val;
515    unsigned short   date;
516    uint32_t         sec = 0;
517    uint32_t         byte = 0;
518
519    msdos_date_unix2dos(fat_fd->mtime, &time_val, &date);
520
521    /*
522     * calculate input for _fat_block_write: convert (cluster num, offset) to
523     * (sector num, new offset)
524     */
525    sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
526    sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
527    /* byte points to start of 32bytes structure */
528    byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
529
530    time_val = CT_LE_W(time_val);
531    ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET,
532                            2, (char *)(&time_val));
533    date = CT_LE_W(date);
534    ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET,
535                            2, (char *)(&date));
536
537    if ( (ret1 < 0) || (ret2 < 0) )
538        return -1;
539
540    return RC_OK;
541}
542
543/* msdos_set_first_cluster_num --
544 *     Write number of first cluster of the file to the disk (to corresponded
545 *     32bytes slot)
546 *
547 * PARAMETERS:
548 *     mt_entry - mount table entry
549 *     fat_fd   - fat-file descriptor
550 *
551 * RETURNS:
552 *     RC_OK on success, or -1 if error occured
553 *
554 */
555int
556msdos_set_first_cluster_num(
557    rtems_filesystem_mount_table_entry_t *mt_entry,
558    fat_file_fd_t                        *fat_fd
559    )
560{
561    ssize_t          ret1 = 0, ret2 = 0;
562    msdos_fs_info_t *fs_info = mt_entry->fs_info;
563    uint32_t         new_cln = fat_fd->cln;
564    uint16_t         le_cl_low = 0;
565    uint16_t         le_cl_hi = 0;
566    uint32_t         sec = 0;
567    uint32_t         byte = 0;
568
569    /*
570     * calculate input for _fat_block_write: convert (cluster num, offset) to
571     * (sector num, new offset)
572     */
573    sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
574    sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
575    /* byte from points to start of 32bytes structure */
576    byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
577
578    le_cl_low = CT_LE_W((uint16_t  )(new_cln & 0x0000FFFF));
579    ret1 = _fat_block_write(mt_entry, sec,
580                            byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
581                            (char *)(&le_cl_low));
582    le_cl_hi = CT_LE_W((uint16_t  )((new_cln & 0xFFFF0000) >> 16));
583    ret2 = _fat_block_write(mt_entry, sec,
584                            byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
585                            (char *)(&le_cl_hi));
586    if ( (ret1 < 0) || (ret2 < 0) )
587        return -1;
588
589    return RC_OK;
590}
591
592
593/* msdos_set_file size --
594 *     Write file size of the file to the disk (to corresponded 32bytes slot)
595 *
596 * PARAMETERS:
597 *     mt_entry - mount table entry
598 *     fat_fd   - fat-file descriptor
599 *
600 * RETURNS:
601 *     RC_OK on success, or -1 if error occured (errno set apropriately).
602 *
603 */
604int
605msdos_set_file_size(
606    rtems_filesystem_mount_table_entry_t *mt_entry,
607    fat_file_fd_t                        *fat_fd
608    )
609{
610    ssize_t          ret = 0;
611    msdos_fs_info_t *fs_info = mt_entry->fs_info;
612    uint32_t         le_new_length = 0;
613    uint32_t         sec = 0;
614    uint32_t         byte = 0;
615
616    sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
617    sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
618    byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1));
619
620    le_new_length = CT_LE_L((fat_fd->fat_file_size));
621    ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
622                           (char *)(&le_new_length));
623    if ( ret < 0 )
624        return -1;
625
626    return RC_OK;
627}
628
629/*
630 * We should not check whether this routine is called for root dir - it
631 * never can happend
632 */
633
634/* msdos_set_first_char4file_name --
635 *     Write first character of the name of the file to the disk (to
636 *     corresponded 32bytes slot)
637 *
638 * PARAMETERS:
639 *     mt_entry - mount table entry
640 *     cl       - number of cluster
641 *     ofs      - offset inside cluster
642 *     fchar    - character to set up
643 *
644 * RETURNS:
645 *     RC_OK on success, or -1 if error occured (errno set apropriately)
646 *
647 */
648int
649msdos_set_first_char4file_name(
650    rtems_filesystem_mount_table_entry_t *mt_entry,
651    uint32_t                              cl,
652    uint32_t                              ofs,
653    unsigned char                         fchar
654    )
655{
656    ssize_t          ret = 0;
657    msdos_fs_info_t *fs_info = mt_entry->fs_info;
658    uint32_t         sec = 0;
659    uint32_t         byte = 0;
660
661    sec = fat_cluster_num_to_sector_num(mt_entry, cl);
662    sec += (ofs >> fs_info->fat.vol.sec_log2);
663    byte = (ofs & (fs_info->fat.vol.bps - 1));
664
665    ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1,
666                           &fchar);
667    if ( ret < 0)
668        return -1;
669
670    return  RC_OK;
671}
672
673/* msdos_dir_is_empty --
674 *     Check whether directory which correspondes to the fat-file descriptor is
675 *     empty.
676 *
677 * PARAMETERS:
678 *     mt_entry - mount table entry
679 *     fat_fd   - fat-file descriptor
680 *     ret_val  - placeholder for result
681 *
682 * RETURNS:
683 *     RC_OK on success, or -1 if error occured
684 *
685 */
686int
687msdos_dir_is_empty(
688    rtems_filesystem_mount_table_entry_t *mt_entry,
689    fat_file_fd_t                        *fat_fd,
690    rtems_boolean                        *ret_val
691    )
692{
693    ssize_t          ret = 0;
694    msdos_fs_info_t *fs_info = mt_entry->fs_info;
695    uint32_t         j = 0, i = 0;
696
697    /* dir is not empty */
698    *ret_val = FALSE;
699
700    while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
701                                  fs_info->fat.vol.bps,
702                                  fs_info->cl_buf)) != FAT_EOF)
703    {
704        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
705            return -1;
706
707        assert(ret == fs_info->fat.vol.bps);
708
709        /* have to look at the DIR_NAME as "raw" 8-bit data */
710        for (i = 0;
711             i < fs_info->fat.vol.bps;
712             i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
713        {
714            if (((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
715                 MSDOS_THIS_DIR_ENTRY_EMPTY) ||
716                (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
717                         MSDOS_SHORT_NAME_LEN) == 0) ||
718                (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
719                         MSDOS_DOTDOT_NAME,
720                         MSDOS_SHORT_NAME_LEN) == 0))
721                continue;
722
723            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
724                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
725            {
726                *ret_val = TRUE;
727                return RC_OK;
728            }
729            return RC_OK;
730        }
731        j++;
732    }
733    *ret_val = TRUE;
734    return RC_OK;
735}
736
737
738/* msdos_find_name_in_fat_file --
739 *     This routine is used in two ways: for a new mode creation (a) or for
740 *     search the node which correspondes to the 'name' parameter (b).
741 *     In case (a) name should be set up to NULL and 'name_dir_entry' should
742 *     point to initialized 32 bytes structure described a new node.
743 *     In case (b) 'name' should contain a valid string.
744 *
745 *     (a): reading fat-file corresponded to directory we are going to create
746 *          node in. If found free slot write contents of name_dir_entry into
747 *          it.
748 *
749 *     (b): reading fat-file corresponded to directory and trying to find slot
750 *          with the name field == name parameter
751 *
752 * PARAMETERS:
753 *     mt_entry       - mount table entry
754 *     fat_fd         - fat-file descriptor
755 *     name           - NULL or name to find
756 *     paux           - identify a node location on the disk -
757 *                      number of cluster and offset inside the cluster
758 *     name_dir_entry - node to create/placeholder for found node
759 *
760 * RETURNS:
761 *     RC_OK on success, or error code if error occured (errno set
762 *     appropriately)
763 *
764 */
765msdos_status_t
766msdos_find_name_in_fat_file(
767    rtems_filesystem_mount_table_entry_t *mt_entry,
768    fat_file_fd_t                        *fat_fd,
769    char                                 *name,
770    fat_auxiliary_t                      *paux,
771    char                                 *name_dir_entry
772    )
773{
774    msdos_status_t   rc = RC_OK;
775    ssize_t          ret = 0;
776    msdos_fs_info_t *fs_info = mt_entry->fs_info;
777    uint32_t         i = 0, j = 0;
778    uint32_t         bts2rd = 0;
779
780    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
781       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
782        bts2rd = fat_fd->fat_file_size;
783    else
784        bts2rd = fs_info->fat.vol.bpc;
785
786    while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd,
787                                fs_info->cl_buf)) != FAT_EOF)
788    {
789        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
790            set_errno_and_return_minus_one(EIO);
791
792        assert(ret == bts2rd);
793
794        /* have to look at the DIR_NAME as "raw" 8-bit data */
795        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
796        {
797            /* is the entry empty ? */
798            if (((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
799                 MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
800                 ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
801                 MSDOS_THIS_DIR_ENTRY_EMPTY))
802            {
803                /* whether we are looking for an empty entry */
804                if (name == NULL)
805                {
806                    /* get current cluster number */
807                    rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
808                                        j * bts2rd, &paux->cln);
809                    if (rc != RC_OK)
810                        return rc;
811
812                    /* offset is computed in bytes */
813                    paux->ofs = i;
814
815                    /* write new node entry */
816                    ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i,
817                                         MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
818                                         (uint8_t *)name_dir_entry);
819                    if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
820                        return -1;
821
822                    /*
823                     * we don't update fat_file_size here - it should not
824                     * increase
825                     */
826                    return RC_OK;
827                }
828
829                /*
830                 * if name != NULL and there is no more entries in the
831                 * directory - return name-not-found
832                 */
833                if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
834                     MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY))
835                    return MSDOS_NAME_NOT_FOUND_ERR;
836            }
837            else
838            {
839                /* entry not empty and name != NULL -> compare names */
840                if (name != NULL)
841                {
842                    if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name,
843                                MSDOS_SHORT_NAME_LEN) == 0)
844                    {
845                        /*
846                         * we get the entry we looked for - fill auxiliary
847                         * structure and copy all 32 bytes of the entry
848                         */
849                        rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
850                                            j * bts2rd, &paux->cln);
851                        if (rc != RC_OK)
852                            return rc;
853
854                        /* offset is computed in bytes */
855                        paux->ofs = i;
856                        memcpy(name_dir_entry,(fs_info->cl_buf + i),
857                               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
858                        return RC_OK;
859                    }
860                }
861            }
862        }
863        j++;
864    }
865    return MSDOS_NAME_NOT_FOUND_ERR;
866}
867
868/* msdos_find_node_by_cluster_num_in_fat_file --
869 *     Find node with specified number of cluster in fat-file.
870 *
871 * PARAMETERS:
872 *     mt_entry  - mount table entry
873 *     fat_fd    - fat-file descriptor
874 *     cl4find   - number of cluster to find
875 *     paux      - identify a node location on the disk -
876 *                 cluster num and offset inside the cluster
877 *     dir_entry - placeholder for found node
878 *
879 * RETURNS:
880 *     RC_OK on success, or error code if error occured
881 *
882 */
883msdos_status_t
884msdos_find_node_by_cluster_num_in_fat_file(
885    rtems_filesystem_mount_table_entry_t *mt_entry,
886    fat_file_fd_t                        *fat_fd,
887    uint32_t                              cl4find,
888    fat_auxiliary_t                      *paux,
889    char                                 *dir_entry
890    )
891{
892    msdos_status_t   rc = RC_OK;
893    ssize_t          ret = 0;
894    msdos_fs_info_t *fs_info = mt_entry->fs_info;
895    uint32_t         bts2rd = 0;
896    uint32_t         i = 0, j = 0;
897
898    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
899       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
900        bts2rd = fat_fd->fat_file_size;
901    else
902        bts2rd = fs_info->fat.vol.bpc;
903
904    while ((ret = fat_file_read(mt_entry, fat_fd, j * bts2rd, bts2rd,
905                                  fs_info->cl_buf)) != FAT_EOF)
906    {
907        if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
908            set_errno_and_return_minus_one( EIO );
909
910        assert(ret == bts2rd);
911
912        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
913        {
914            /* if this and all rest entries are empty - return not-found */
915            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
916                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
917                return MSDOS_NAME_NOT_FOUND_ERR;
918
919            /* have to look at the DIR_NAME as "raw" 8-bit data */
920            /* if this entry is empty - skip it */
921            if ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
922                MSDOS_THIS_DIR_ENTRY_EMPTY)
923                continue;
924
925            /* if get a non-empty entry - compare clusters num */
926            if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find)
927            {
928                /* on success fill aux structure and copy all 32 bytes */
929                rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd,
930                                    &paux->cln);
931                if (rc != RC_OK)
932                    return rc;
933
934                paux->ofs = i;
935                memcpy(dir_entry, fs_info->cl_buf + i,
936                       MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
937                return RC_OK;
938            }
939        }
940        j++;
941    }
942    return MSDOS_NAME_NOT_FOUND_ERR;
943}
Note: See TracBrowser for help on using the repository browser.