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

Last change on this file since d9c2dce0 was d9c2dce0, checked in by Chris Johns <chrisj@…>, on 07/02/03 at 13:58:38

Patch from Victor V. Vengerov <vvv@…> to remove Linux code.

  • Property mode set to 100644
File size: 29.9 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.OARcorp.com/rtems/license.html.
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    unsigned 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 */
255int
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    int              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    unsigned32       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                             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    unsigned32                            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    unsigned char    dot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
389    unsigned char    dotdot_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
390    unsigned char    cur_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
391    unsigned32       cl4find = 0;
392 
393    memset(dot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); 
394    memset(dotdot_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
395    memset(cur_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
396 
397    /*
398     * open fat-file corresponded to ".."
399     */
400    rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
401    if (rc != RC_OK)
402        return rc;
403 
404    fat_fd->info_cln = paux->cln;
405    fat_fd->info_ofs = paux->ofs;
406    fat_fd->cln = cln;
407    fat_fd->fat_file_type = FAT_DIRECTORY;
408    fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
409   
410    fat_fd->map.file_cln = 0;
411    fat_fd->map.disk_cln = fat_fd->cln;
412
413    rc = fat_file_size(mt_entry, fat_fd);
414    if (rc != RC_OK)
415    {
416        fat_file_close(mt_entry, fat_fd);
417        return rc;
418    } 
419 
420    /* find "." node in opened directory */
421    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOT_NAME, paux,
422                                     dot_node);
423                                   
424    if (rc != RC_OK)
425    {
426        fat_file_close(mt_entry, fat_fd);
427        return rc;
428    }
429 
430    /* find ".." node in opened directory */
431    rc = msdos_find_name_in_fat_file(mt_entry, fat_fd, MSDOS_DOTDOT_NAME, paux,
432                                     dotdot_node);
433                                   
434    if (rc != RC_OK)
435    {
436        fat_file_close(mt_entry, fat_fd);
437        return rc;
438    }
439
440    cl4find = MSDOS_EXTRACT_CLUSTER_NUM(dot_node);
441 
442    /* close fat-file corresponded to ".." directory */
443    rc = fat_file_close(mt_entry, fat_fd);
444    if ( rc != RC_OK )
445        return rc;
446
447    if ( (MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
448    {
449        /*
450         * we handle root dir for all FAT types in the same way with the
451         * ordinary directories ( through fat_file_* calls )
452         */
453        paux->cln = FAT_ROOTDIR_CLUSTER_NUM;
454        paux->ofs = 0;
455    }
456
457    /* open fat-file corresponded to second ".." */
458    rc = fat_file_open(mt_entry, paux->cln, paux->ofs, &fat_fd);
459    if (rc != RC_OK)
460        return rc;
461
462    fat_fd->info_cln = paux->cln;
463    fat_fd->info_ofs = paux->ofs;
464
465    if ((MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node)) == 0)
466        fat_fd->cln = fs_info->fat.vol.rdir_cl;
467    else
468        fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(dotdot_node);
469
470    fat_fd->fat_file_type = FAT_DIRECTORY;
471    fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;
472   
473    fat_fd->map.file_cln = 0;
474    fat_fd->map.disk_cln = fat_fd->cln;
475
476    rc = fat_file_size(mt_entry, fat_fd);
477    if (rc != RC_OK)
478    {
479        fat_file_close(mt_entry, fat_fd);
480        return rc;
481    } 
482 
483    /* in this directory find slot with specified cluster num */
484    rc = msdos_find_node_by_cluster_num_in_fat_file(mt_entry, fat_fd, cl4find,
485                                                    paux, dir_entry);
486    if (rc != RC_OK)
487    {
488        fat_file_close(mt_entry, fat_fd);
489        return rc;
490    }
491    rc = fat_file_close(mt_entry, fat_fd);
492    return rc;
493}
494
495
496/* msdos_set_dir_wrt_time_and_date --
497 *     Write last write date and time for a file to the disk (to corresponded
498 *     32bytes node)     
499 *
500 * PARAMETERS:
501 *     mt_entry - mount table entry
502 *     fat_fd   - fat-file descriptor
503 *
504 * RETURNS:
505 *     RC_OK on success, or -1 if error occured (errno set apropriately).
506 *
507 */
508int
509msdos_set_dir_wrt_time_and_date(
510    rtems_filesystem_mount_table_entry_t *mt_entry,
511    fat_file_fd_t                        *fat_fd
512    )
513{
514    ssize_t          ret1 = 0, ret2 = 0;
515    msdos_fs_info_t *fs_info = mt_entry->fs_info;
516    unsigned short   time_val;
517    unsigned short   date;
518    unsigned32       sec = 0;
519    unsigned32       byte = 0;
520 
521    msdos_date_unix2dos(fat_fd->mtime, &time_val, &date);
522 
523    /*
524     * calculate input for _fat_block_write: convert (cluster num, offset) to
525     * (sector num, new offset)
526     */
527    sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
528    sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
529    /* byte points to start of 32bytes structure */
530    byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
531   
532    time_val = CT_LE_W(time_val);
533    ret1 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WTIME_OFFSET,
534                            2, (char *)(&time_val));
535    date = CT_LE_W(date);
536    ret2 = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_WDATE_OFFSET,
537                            2, (char *)(&date));
538
539    if ( (ret1 < 0) || (ret2 < 0) )
540        return -1;
541
542    return RC_OK;
543}
544
545/* msdos_set_first_cluster_num --
546 *     Write number of first cluster of the file to the disk (to corresponded
547 *     32bytes slot)     
548 *
549 * PARAMETERS:
550 *     mt_entry - mount table entry
551 *     fat_fd   - fat-file descriptor
552 *
553 * RETURNS:
554 *     RC_OK on success, or -1 if error occured
555 *
556 */
557int
558msdos_set_first_cluster_num(
559    rtems_filesystem_mount_table_entry_t *mt_entry,
560    fat_file_fd_t                        *fat_fd
561    )
562{
563    ssize_t          ret1 = 0, ret2 = 0;
564    msdos_fs_info_t *fs_info = mt_entry->fs_info;
565    unsigned32       new_cln = fat_fd->cln;
566    unsigned16       le_cl_low = 0;
567    unsigned16       le_cl_hi = 0; 
568    unsigned32       sec = 0;
569    unsigned32       byte = 0;
570
571    /*
572     * calculate input for _fat_block_write: convert (cluster num, offset) to
573     * (sector num, new offset)
574     */
575    sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
576    sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
577    /* byte from points to start of 32bytes structure */
578    byte = fat_fd->info_ofs & (fs_info->fat.vol.bps - 1);
579 
580    le_cl_low = CT_LE_W((unsigned16)(new_cln & 0x0000FFFF));
581    ret1 = _fat_block_write(mt_entry, sec,
582                            byte + MSDOS_FIRST_CLUSTER_LOW_OFFSET, 2,
583                            (char *)(&le_cl_low));
584    le_cl_hi = CT_LE_W((unsigned16)((new_cln & 0xFFFF0000) >> 16));
585    ret2 = _fat_block_write(mt_entry, sec,
586                            byte + MSDOS_FIRST_CLUSTER_HI_OFFSET, 2,
587                            (char *)(&le_cl_hi));
588    if ( (ret1 < 0) || (ret2 < 0) )
589        return -1;
590
591    return RC_OK;
592}
593
594
595/* msdos_set_file size --
596 *     Write file size of the file to the disk (to corresponded 32bytes slot)     
597 *
598 * PARAMETERS:
599 *     mt_entry - mount table entry
600 *     fat_fd   - fat-file descriptor
601 *
602 * RETURNS:
603 *     RC_OK on success, or -1 if error occured (errno set apropriately).
604 *
605 */
606int
607msdos_set_file_size(
608    rtems_filesystem_mount_table_entry_t *mt_entry,
609    fat_file_fd_t                        *fat_fd
610    )
611{
612    ssize_t          ret = 0;
613    msdos_fs_info_t *fs_info = mt_entry->fs_info;
614    unsigned32       le_new_length = 0;
615    unsigned32       sec = 0;
616    unsigned32       byte = 0;
617
618    sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->info_cln);
619    sec += (fat_fd->info_ofs >> fs_info->fat.vol.sec_log2);
620    byte = (fat_fd->info_ofs & (fs_info->fat.vol.bps - 1));
621
622    le_new_length = CT_LE_L((fat_fd->fat_file_size));
623    ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_SIZE_OFFSET, 4,
624                           (char *)(&le_new_length));
625    if ( ret < 0 )
626        return -1;
627
628    return RC_OK;
629}
630
631/*
632 * We should not check whether this routine is called for root dir - it
633 * never can happend
634 */
635
636/* msdos_set_first_char4file_name --
637 *     Write first character of the name of the file to the disk (to
638 *     corresponded 32bytes slot)     
639 *
640 * PARAMETERS:
641 *     mt_entry - mount table entry
642 *     cl       - number of cluster
643 *     ofs      - offset inside cluster
644 *     fchar    - character to set up
645 *
646 * RETURNS:
647 *     RC_OK on success, or -1 if error occured (errno set apropriately)
648 *
649 */
650int
651msdos_set_first_char4file_name(
652    rtems_filesystem_mount_table_entry_t *mt_entry,
653    unsigned32                            cl,
654    unsigned32                            ofs,
655    unsigned char                         fchar
656    )
657{
658    ssize_t          ret = 0;
659    msdos_fs_info_t *fs_info = mt_entry->fs_info;
660    unsigned32       sec = 0;
661    unsigned32       byte = 0;
662
663    sec = fat_cluster_num_to_sector_num(mt_entry, cl);
664    sec += (ofs >> fs_info->fat.vol.sec_log2);
665    byte = (ofs & (fs_info->fat.vol.bps - 1));
666
667    ret = _fat_block_write(mt_entry, sec, byte + MSDOS_FILE_NAME_OFFSET, 1,
668                           &fchar);
669    if ( ret < 0)
670        return -1;
671
672    return  RC_OK;
673}                       
674
675/* msdos_dir_is_empty --
676 *     Check whether directory which correspondes to the fat-file descriptor is
677 *     empty.     
678 *
679 * PARAMETERS:
680 *     mt_entry - mount table entry
681 *     fat_fd   - fat-file descriptor   
682 *     ret_val  - placeholder for result
683 *
684 * RETURNS:
685 *     RC_OK on success, or -1 if error occured
686 *
687 */
688int
689msdos_dir_is_empty(
690    rtems_filesystem_mount_table_entry_t *mt_entry,
691    fat_file_fd_t                        *fat_fd,
692    rtems_boolean                        *ret_val
693    )
694{
695    ssize_t          ret = 0;
696    msdos_fs_info_t *fs_info = mt_entry->fs_info;
697    unsigned32       j = 0, i = 0;
698 
699    /* dir is not empty */
700    *ret_val = FALSE;
701
702    while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
703                                  fs_info->fat.vol.bps,
704                                  fs_info->cl_buf)) != FAT_EOF)
705    {
706        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
707            return -1;
708
709        assert(ret == fs_info->fat.vol.bps);
710       
711        for (i = 0;
712             i < fs_info->fat.vol.bps;
713             i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
714        {
715            if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
716                 MSDOS_THIS_DIR_ENTRY_EMPTY) ||
717                (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
718                         MSDOS_SHORT_NAME_LEN) == 0) ||
719                (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
720                         MSDOS_DOTDOT_NAME,
721                         MSDOS_SHORT_NAME_LEN) == 0))
722                continue;
723
724            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) == 
725                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
726            {
727                *ret_val = TRUE;
728                return RC_OK;
729            }
730            return RC_OK;
731        }   
732        j++;
733    }
734    *ret_val = TRUE;
735    return RC_OK;
736}
737
738
739/* msdos_find_name_in_fat_file --
740 *     This routine is used in two ways: for a new mode creation (a) or for
741 *     search the node which correspondes to the 'name' parameter (b).
742 *     In case (a) name should be set up to NULL and 'name_dir_entry' should
743 *     point to initialized 32 bytes structure described a new node.
744 *     In case (b) 'name' should contain a valid string.
745 *
746 *     (a): reading fat-file corresponded to directory we are going to create
747 *          node in. If found free slot write contents of name_dir_entry into
748 *          it. 
749 *
750 *     (b): reading fat-file corresponded to directory and trying to find slot
751 *          with the name field == name parameter
752 *
753 * PARAMETERS:
754 *     mt_entry       - mount table entry
755 *     fat_fd         - fat-file descriptor   
756 *     name           - NULL or name to find
757 *     paux           - identify a node location on the disk -
758 *                      number of cluster and offset inside the cluster
759 *     name_dir_entry - node to create/placeholder for found node
760 *
761 * RETURNS:
762 *     RC_OK on success, or error code if error occured (errno set
763 *     appropriately)
764 *
765 */
766int
767msdos_find_name_in_fat_file(
768    rtems_filesystem_mount_table_entry_t *mt_entry,
769    fat_file_fd_t                        *fat_fd,
770    char                                 *name,
771    fat_auxiliary_t                      *paux,
772    char                                 *name_dir_entry
773    )
774{
775    int              rc = RC_OK;
776    ssize_t          ret = 0;
777    msdos_fs_info_t *fs_info = mt_entry->fs_info;
778    unsigned32       i = 0, j = 0;
779    unsigned32       bts2rd = 0;
780
781    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
782       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
783        bts2rd = fat_fd->fat_file_size; 
784    else
785        bts2rd = fs_info->fat.vol.bpc;
786 
787    while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd,
788                                fs_info->cl_buf)) != FAT_EOF)
789    {
790        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
791            set_errno_and_return_minus_one(EIO);
792           
793        assert(ret == bts2rd);   
794
795        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
796        {
797            /* is the entry empty ? */
798            if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
799                 MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
800                 ((*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                                         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 */
883int
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    unsigned32                            cl4find,
888    fat_auxiliary_t                      *paux,
889    char                                 *dir_entry
890    )
891{
892    int              rc = RC_OK;
893    ssize_t          ret = 0;
894    msdos_fs_info_t *fs_info = mt_entry->fs_info;
895    unsigned32       bts2rd = 0; 
896    unsigned32       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            /* if this entry is empty - skip it */
920            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
921                MSDOS_THIS_DIR_ENTRY_EMPTY)
922                continue;
923
924            /* if get a non-empty entry - compare clusters num */
925            if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find)
926            {
927                /* on success fill aux structure and copy all 32 bytes */
928                rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd,
929                                    &paux->cln);
930                if (rc != RC_OK)
931                    return rc;
932
933                paux->ofs = i;
934                memcpy(dir_entry, fs_info->cl_buf + i,
935                       MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
936                return RC_OK;
937            }
938        }                         
939        j++;
940    }                       
941    return MSDOS_NAME_NOT_FOUND_ERR;
942}
Note: See TracBrowser for help on using the repository browser.