source: rtems/cpukit/libfs/src/dosfs/fat_file.c @ 796967c

4.115
Last change on this file since 796967c was 796967c, checked in by Sebastian Huber <sebastian.huber@…>, on 02/28/12 at 16:19:49

libblock: Change bdbuf API

The functions

o rtems_bdbuf_get(),
o rtems_bdbuf_read(),
o rtems_bdbuf_syncdev(), and
o rtems_bdbuf_purge_dev(),

use now the disk device instead of the device identifier. This makes
bdbuf independent of rtems_disk_obtain() and rtems_disk_release(). It
is the responsiblity of the file system to obtain the disk device. This
also reduces the overhead to get a buffer.

The key for the AVL tree uses now the disk device instead of the device
identifier. The pointer is interpreted as an unsigned integer. This
reduces the memory overhead and makes the comparison operation a bit
faster.

Removed function rtems_bdbuf_purge_major(). This function was too
destructive and could have unpredictable side effects.

  • Property mode set to 100644
File size: 27.1 KB
Line 
1/*
2 *  fat_file.c
3 *
4 *  General operations on "fat-file"
5 *
6 * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia
7 * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru>
8 *
9 * @(#) $Id$
10 *
11 */
12
13#define MSDOS_TRACE 1
14
15#if HAVE_CONFIG_H
16#include "config.h"
17#endif
18
19#include <sys/types.h>
20#include <sys/stat.h>
21#include <fcntl.h>
22#include <unistd.h>
23#include <stdarg.h>
24#include <errno.h>
25#include <stdlib.h>
26#include <assert.h>
27#include <time.h>
28
29#include <rtems/libio_.h>
30
31#include "fat.h"
32#include "fat_fat_operations.h"
33#include "fat_file.h"
34
35static inline void
36_hash_insert(rtems_chain_control *hash, uint32_t   key1, uint32_t   key2,
37             fat_file_fd_t *el);
38
39static inline void
40_hash_delete(rtems_chain_control *hash, uint32_t   key1, uint32_t   key2,
41             fat_file_fd_t *el);
42
43static inline int
44_hash_search(
45    rtems_filesystem_mount_table_entry_t  *mt_entry,
46    rtems_chain_control                   *hash,
47    uint32_t                               key1,
48    uint32_t                               key2,
49    fat_file_fd_t                                          **ret
50);
51
52static off_t
53fat_file_lseek(
54    rtems_filesystem_mount_table_entry_t  *mt_entry,
55    fat_file_fd_t                         *fat_fd,
56    uint32_t                               file_cln,
57    uint32_t                              *disk_cln
58);
59
60/* fat_file_open --
61 *     Open fat-file. Two hash tables are accessed by key
62 *     constructed from cluster num and offset of the node (i.e.
63 *     files/directories are distinguished by location on the disk).
64 *     First, hash table("vhash") consists of fat-file descriptors corresponded
65 *     to "valid" files is accessed. Search is made by 2 fields equal to key
66 *     constructed. If descriptor is found in the "vhash" - return it.
67 *     Otherwise search is made in hash table("rhash") consits of fat-file
68 *     descriptors corresponded to "removed-but-still-open" files with the
69 *     same keys.
70 *     If search failed, new fat-file descriptor is added to "vhash"
71 *     with both key fields equal to constructed key. Otherwise new fat-file
72 *     descriptor is added to "vhash" with first key field equal to key
73 *     constructed and the second equal to an unique (unique among all values
74 *     of second key fields) value.
75 *
76 * PARAMETERS:
77 *     mt_entry - mount table entry
78 *     pos      - cluster and offset of the node
79 *     fat_fd   - placeholder for returned fat-file descriptor
80 *
81 * RETURNS:
82 *     RC_OK and pointer to opened descriptor on success, or -1 if error
83 *     occured (errno set appropriately)
84 */
85int
86fat_file_open(
87    rtems_filesystem_mount_table_entry_t  *mt_entry,
88    fat_dir_pos_t                         *dir_pos,
89    fat_file_fd_t                        **fat_fd
90    )
91{
92    int            rc = RC_OK;
93    fat_fs_info_t *fs_info = mt_entry->fs_info;
94    fat_file_fd_t *lfat_fd = NULL;
95    uint32_t       key = 0;
96
97    /* construct key */
98    key = fat_construct_key(mt_entry, &dir_pos->sname);
99
100    /* access "valid" hash table */
101    rc = _hash_search(mt_entry, fs_info->vhash, key, 0, &lfat_fd);
102    if ( rc == RC_OK )
103    {
104        /* return pointer to fat_file_descriptor allocated before */
105        (*fat_fd) = lfat_fd;
106        lfat_fd->links_num++;
107        return rc;
108    }
109
110    /* access "removed-but-still-open" hash table */
111    rc = _hash_search(mt_entry, fs_info->rhash, key, key, &lfat_fd);
112
113    lfat_fd = (*fat_fd) = (fat_file_fd_t*)malloc(sizeof(fat_file_fd_t));
114    if ( lfat_fd == NULL )
115        rtems_set_errno_and_return_minus_one( ENOMEM );
116
117    memset(lfat_fd, 0, sizeof(fat_file_fd_t));
118
119    lfat_fd->links_num = 1;
120    lfat_fd->flags &= ~FAT_FILE_REMOVED;
121    lfat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
122
123    lfat_fd->dir_pos = *dir_pos;
124
125    if ( rc != RC_OK )
126        lfat_fd->ino = key;
127    else
128    {
129        lfat_fd->ino = fat_get_unique_ino(mt_entry);
130
131        if ( lfat_fd->ino == 0 )
132        {
133            free((*fat_fd));
134            /*
135             * XXX: kernel resource is unsufficient, but not the memory,
136             * but there is no suitable errno :(
137             */
138            rtems_set_errno_and_return_minus_one( ENOMEM );
139        }
140    }
141    _hash_insert(fs_info->vhash, key, lfat_fd->ino, lfat_fd);
142
143    /*
144     * other fields of fat-file descriptor will be initialized on upper
145     * level
146     */
147
148    return RC_OK;
149}
150
151
152/* fat_file_reopen --
153 *     Increment by 1 number of links
154 *
155 * PARAMETERS:
156 *     fat_fd - fat-file descriptor
157 *
158 * RETURNS:
159 *     RC_OK
160 */
161int
162fat_file_reopen(fat_file_fd_t *fat_fd)
163{
164    fat_fd->links_num++;
165    return RC_OK;
166}
167
168/* fat_file_close --
169 *     Close fat-file. If count of links to fat-file
170 *     descriptor is greater than 1 (i.e. somebody esle holds pointer
171 *     to this descriptor) just decrement it. Otherwise
172 *     do the following. If this descriptor corresponded to removed fat-file
173 *     then free clusters contained fat-file data, delete descriptor from
174 *     "rhash" table and free memory allocated by descriptor. If descriptor
175 *     correspondes to non-removed fat-file and 'ino' field has value from
176 *     unique inode numbers pool then set count of links to descriptor to zero
177 *     and leave it in hash, otherwise delete descriptor from "vhash" and free
178 *     memory allocated by the descriptor
179 *
180 * PARAMETERS:
181 *     mt_entry - mount table entry
182 *     fat_fd   - fat-file descriptor
183 *
184 * RETURNS:
185 *     RC_OK, or -1 if error occured (errno set appropriately)
186 */
187int
188fat_file_close(
189    rtems_filesystem_mount_table_entry_t *mt_entry,
190    fat_file_fd_t                        *fat_fd
191    )
192{
193    int            rc = RC_OK;
194    fat_fs_info_t *fs_info = mt_entry->fs_info;
195    uint32_t       key = 0;
196
197    /*
198     * if links_num field of fat-file descriptor is greater than 1
199     * decrement the count of links and return
200     */
201    if (fat_fd->links_num > 1)
202    {
203        fat_fd->links_num--;
204        return rc;
205    }
206
207    key = fat_construct_key(mt_entry, &fat_fd->dir_pos.sname);
208
209    if (fat_fd->flags & FAT_FILE_REMOVED)
210    {
211        rc = fat_file_truncate(mt_entry, fat_fd, 0);
212        if ( rc != RC_OK )
213            return rc;
214
215        _hash_delete(fs_info->rhash, key, fat_fd->ino, fat_fd);
216
217        if ( fat_ino_is_unique(mt_entry, fat_fd->ino) )
218            fat_free_unique_ino(mt_entry, fat_fd->ino);
219
220        free(fat_fd);
221    }
222    else
223    {
224        if (fat_ino_is_unique(mt_entry, fat_fd->ino))
225        {
226            fat_fd->links_num = 0;
227        }
228        else
229        {
230            _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
231            free(fat_fd);
232        }
233    }
234    /*
235     * flush any modified "cached" buffer back to disk
236     */
237    rc = fat_buf_release(fs_info);
238
239    return rc;
240}
241
242/* fat_file_read --
243 *     Read 'count' bytes from 'start' position from fat-file. This
244 *     interface hides the architecture of fat-file, represents it as
245 *     linear file
246 *
247 * PARAMETERS:
248 *     mt_entry - mount table entry
249 *     fat_fd   - fat-file descriptor
250 *     start    - offset in fat-file (in bytes) to read from
251 *     count    - count of bytes to read
252 *     buf      - buffer provided by user
253 *
254 * RETURNS:
255 *     the number of bytes read on success, or -1 if error occured (errno
256 *     set appropriately)
257 */
258ssize_t
259fat_file_read(
260    rtems_filesystem_mount_table_entry_t *mt_entry,
261    fat_file_fd_t                        *fat_fd,
262    uint32_t                              start,
263    uint32_t                              count,
264    uint8_t                              *buf
265)
266{
267    int            rc = RC_OK;
268    ssize_t        ret = 0;
269    fat_fs_info_t *fs_info = mt_entry->fs_info;
270    uint32_t       cmpltd = 0;
271    uint32_t       cur_cln = 0;
272    uint32_t       cl_start = 0;
273    uint32_t       save_cln = 0;
274    uint32_t       ofs = 0;
275    uint32_t       save_ofs;
276    uint32_t       sec = 0;
277    uint32_t       byte = 0;
278    uint32_t       c = 0;
279
280    /* it couldn't be removed - otherwise cache update will be broken */
281    if (count == 0)
282        return cmpltd;
283
284    /*
285     * >= because start is offset and computed from 0 and file_size
286     * computed from 1
287     */
288    if ( start >= fat_fd->fat_file_size )
289        return FAT_EOF;
290
291    if ((count > fat_fd->fat_file_size) ||
292        (start > fat_fd->fat_file_size - count))
293        count = fat_fd->fat_file_size - start;
294
295    if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
296        (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
297    {
298        sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
299        sec += (start >> fs_info->vol.sec_log2);
300        byte = start & (fs_info->vol.bps - 1);
301
302        ret = _fat_block_read(mt_entry, sec, byte, count, buf);
303        if ( ret < 0 )
304            return -1;
305
306        return ret;
307    }
308
309    cl_start = start >> fs_info->vol.bpc_log2;
310    save_ofs = ofs = start & (fs_info->vol.bpc - 1);
311
312    rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
313    if (rc != RC_OK)
314        return rc;
315
316    while (count > 0)
317    {
318        c = MIN(count, (fs_info->vol.bpc - ofs));
319
320        sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
321        sec += (ofs >> fs_info->vol.sec_log2);
322        byte = ofs & (fs_info->vol.bps - 1);
323
324        ret = _fat_block_read(mt_entry, sec, byte, c, buf + cmpltd);
325        if ( ret < 0 )
326            return -1;
327
328        count -= c;
329        cmpltd += c;
330        save_cln = cur_cln;
331        rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
332        if ( rc != RC_OK )
333            return rc;
334
335        ofs = 0;
336    }
337
338    /* update cache */
339    /* XXX: check this - I'm not sure :( */
340    fat_fd->map.file_cln = cl_start +
341                           ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
342    fat_fd->map.disk_cln = save_cln;
343
344    return cmpltd;
345}
346
347/* fat_file_write --
348 *     Write 'count' bytes of data from user supplied buffer to fat-file
349 *     starting at offset 'start'. This interface hides the architecture
350 *     of fat-file, represents it as linear file
351 *
352 * PARAMETERS:
353 *     mt_entry - mount table entry
354 *     fat_fd   - fat-file descriptor
355 *     start    - offset(in bytes) to write from
356 *     count    - count
357 *     buf      - buffer provided by user
358 *
359 * RETURNS:
360 *     number of bytes actually written to the file on success, or -1 if
361 *     error occured (errno set appropriately)
362 */
363ssize_t
364fat_file_write(
365    rtems_filesystem_mount_table_entry_t *mt_entry,
366    fat_file_fd_t                        *fat_fd,
367    uint32_t                              start,
368    uint32_t                              count,
369    const uint8_t                        *buf
370    )
371{
372    int            rc = 0;
373    ssize_t        ret = 0;
374    fat_fs_info_t *fs_info = mt_entry->fs_info;
375    uint32_t       cmpltd = 0;
376    uint32_t       cur_cln = 0;
377    uint32_t       save_cln = 0; /* FIXME: This might be incorrect, cf. below */
378    uint32_t       cl_start = 0;
379    uint32_t       ofs = 0;
380    uint32_t       save_ofs;
381    uint32_t       sec = 0;
382    uint32_t       byte = 0;
383    uint32_t       c = 0;
384
385    if ( count == 0 )
386        return cmpltd;
387
388    if ( start > fat_fd->fat_file_size )
389        rtems_set_errno_and_return_minus_one( EIO );
390
391    if ((count > fat_fd->size_limit) ||
392        (start > fat_fd->size_limit - count))
393        rtems_set_errno_and_return_minus_one( EIO );
394
395    rc = fat_file_extend(mt_entry, fat_fd, start + count, &c);
396    if (rc != RC_OK)
397        return rc;
398
399    /*
400     * check whether there was enough room on device to locate
401     * file of 'start + count' bytes
402     */
403    if (c != (start + count))
404        count = c - start;
405
406    if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
407        (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
408    {
409        sec = fat_cluster_num_to_sector_num(mt_entry, fat_fd->cln);
410        sec += (start >> fs_info->vol.sec_log2);
411        byte = start & (fs_info->vol.bps - 1);
412
413        ret = _fat_block_write(mt_entry, sec, byte, count, buf);
414        if ( ret < 0 )
415            return -1;
416
417        return ret;
418    }
419
420    cl_start = start >> fs_info->vol.bpc_log2;
421    save_ofs = ofs = start & (fs_info->vol.bpc - 1);
422
423    rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
424    if (rc != RC_OK)
425        return rc;
426
427    while (count > 0)
428    {
429        c = MIN(count, (fs_info->vol.bpc - ofs));
430
431        sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
432        sec += (ofs >> fs_info->vol.sec_log2);
433        byte = ofs & (fs_info->vol.bps - 1);
434
435        ret = _fat_block_write(mt_entry, sec, byte, c, buf + cmpltd);
436        if ( ret < 0 )
437            return -1;
438
439        count -= c;
440        cmpltd += c;
441        save_cln = cur_cln;
442        rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
443        if ( rc != RC_OK )
444            return rc;
445
446        ofs = 0;
447    }
448
449    /* update cache */
450    /* XXX: check this - I'm not sure :( */
451    fat_fd->map.file_cln = cl_start +
452                           ((save_ofs + cmpltd - 1) >> fs_info->vol.bpc_log2);
453    fat_fd->map.disk_cln = save_cln;
454
455    return cmpltd;
456}
457
458/* fat_file_extend --
459 *     Extend fat-file. If new length less than current fat-file size -
460 *     do nothing. Otherwise calculate necessary count of clusters to add,
461 *     allocate it and add new clusters chain to the end of
462 *     existing clusters chain.
463 *
464 * PARAMETERS:
465 *     mt_entry   - mount table entry
466 *     fat_fd     - fat-file descriptor
467 *     new_length - new length
468 *     a_length   - placeholder for result - actual new length of file
469 *
470 * RETURNS:
471 *     RC_OK and new length of file on success, or -1 if error occured (errno
472 *     set appropriately)
473 */
474int
475fat_file_extend(
476    rtems_filesystem_mount_table_entry_t *mt_entry,
477    fat_file_fd_t                        *fat_fd,
478    uint32_t                              new_length,
479    uint32_t                             *a_length
480    )
481{
482    int            rc = RC_OK;
483    fat_fs_info_t *fs_info = mt_entry->fs_info;
484    uint32_t       chain = 0;
485    uint32_t       bytes2add = 0;
486    uint32_t       cls2add = 0;
487    uint32_t       old_last_cl;
488    uint32_t       last_cl = 0;
489    uint32_t       bytes_remain = 0;
490    uint32_t       cls_added;
491
492    *a_length = new_length;
493
494    if (new_length <= fat_fd->fat_file_size)
495        return RC_OK;
496
497    if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
498        (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
499        rtems_set_errno_and_return_minus_one( ENOSPC );
500
501    bytes_remain = (fs_info->vol.bpc -
502                   (fat_fd->fat_file_size & (fs_info->vol.bpc - 1))) &
503                   (fs_info->vol.bpc - 1);
504
505    bytes2add = new_length - fat_fd->fat_file_size;
506
507    if (bytes2add > bytes_remain)
508        bytes2add -= bytes_remain;
509    else
510        bytes2add = 0;
511
512    /*
513     * if in last cluster allocated for the file there is enough room to
514     * handle extention (hence we don't need to add even one cluster to the
515     * file ) - return
516     */
517    if (bytes2add == 0)
518        return RC_OK;
519
520    cls2add = ((bytes2add - 1) >> fs_info->vol.bpc_log2) + 1;
521
522    rc = fat_scan_fat_for_free_clusters(mt_entry, &chain, cls2add,
523                                        &cls_added, &last_cl);
524
525    /* this means that low level I/O error occured */
526    if (rc != RC_OK)
527        return rc;
528
529    /* this means that no space left on device */
530    if ((cls_added == 0) && (bytes_remain == 0))
531        rtems_set_errno_and_return_minus_one(ENOSPC);
532
533    /*  check wether we satisfied request for 'cls2add' clusters */
534    if (cls2add != cls_added)
535        *a_length = new_length -
536                    ((cls2add - cls_added - 1) << fs_info->vol.bpc_log2) -
537                    (bytes2add & (fs_info->vol.bpc - 1));
538
539    /* add new chain to the end of existed */
540    if ( fat_fd->fat_file_size == 0 )
541    {
542        fat_fd->map.disk_cln = fat_fd->cln = chain;
543        fat_fd->map.file_cln = 0;
544    }
545    else
546    {
547        if (fat_fd->map.last_cln != FAT_UNDEFINED_VALUE)
548        {
549            old_last_cl = fat_fd->map.last_cln;
550        }
551        else
552        {
553            rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
554                                (fat_fd->fat_file_size - 1), &old_last_cl);
555            if ( rc != RC_OK )
556            {
557                fat_free_fat_clusters_chain(mt_entry, chain);
558                return rc;
559            }
560        }
561
562        rc = fat_set_fat_cluster(mt_entry, old_last_cl, chain);
563        if ( rc != RC_OK )
564        {
565            fat_free_fat_clusters_chain(mt_entry, chain);
566            return rc;
567        }
568        fat_buf_release(fs_info);
569    }
570
571    /* update number of the last cluster of the file if it changed */
572    if (cls_added != 0)
573    {
574        fat_fd->map.last_cln = last_cl;
575        if (fat_fd->fat_file_type == FAT_DIRECTORY)
576        {
577            rc = fat_init_clusters_chain(mt_entry, chain);
578            if ( rc != RC_OK )
579            {
580                fat_free_fat_clusters_chain(mt_entry, chain);
581                return rc;
582            }
583        }
584    }
585
586    fat_fd->fat_file_size = new_length;
587
588    return RC_OK;
589}
590
591/* fat_file_truncate --
592 *     Truncate fat-file. If new length greater than current fat-file size -
593 *     do nothing. Otherwise find first cluster to free and free all clusters
594 *     in the chain starting from this cluster.
595 *
596 * PARAMETERS:
597 *     mt_entry   - mount table entry
598 *     fat_fd     - fat-file descriptor
599 *     new_length - new length
600 *
601 * RETURNS:
602 *     RC_OK on success, or -1 if error occured (errno set appropriately)
603 */
604int
605fat_file_truncate(
606    rtems_filesystem_mount_table_entry_t *mt_entry,
607    fat_file_fd_t                        *fat_fd,
608    uint32_t                              new_length
609    )
610{
611    int            rc = RC_OK;
612    fat_fs_info_t *fs_info = mt_entry->fs_info;
613    uint32_t       cur_cln = 0;
614    uint32_t       cl_start = 0;
615    uint32_t       new_last_cln = FAT_UNDEFINED_VALUE;
616
617
618    if ( new_length >= fat_fd->fat_file_size )
619        return rc;
620
621    assert(fat_fd->fat_file_size);
622
623    cl_start = (new_length + fs_info->vol.bpc - 1) >> fs_info->vol.bpc_log2;
624
625    if ((cl_start << fs_info->vol.bpc_log2) >= fat_fd->fat_file_size)
626        return RC_OK;
627
628    if (cl_start != 0)
629    {
630        rc = fat_file_lseek(mt_entry, fat_fd, cl_start - 1, &new_last_cln);
631        if (rc != RC_OK)
632            return rc;
633
634    }
635
636    rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
637    if (rc != RC_OK)
638        return rc;
639
640    rc = fat_free_fat_clusters_chain(mt_entry, cur_cln);
641    if (rc != RC_OK)
642        return rc;
643
644    if (cl_start != 0)
645    {
646        rc = fat_set_fat_cluster(mt_entry, new_last_cln, FAT_GENFAT_EOC);
647        if ( rc != RC_OK )
648            return rc;
649        fat_fd->map.file_cln = cl_start - 1;
650        fat_fd->map.disk_cln = new_last_cln;
651        fat_fd->map.last_cln = new_last_cln;
652    }
653    return RC_OK;
654}
655
656/* fat_file_ioctl --
657 *     F_CLU_NUM:
658 *         make mapping between serial number of the cluster in fat-file and
659 *         its real number on the volume
660 *
661 * PARAMETERS:
662 *     fat_fd     - fat-file descriptor
663 *     mt_entry   - mount table entry
664 *     cmd        - command
665 *     ...
666 *
667 * RETURNS:
668 *     RC_OK on success, or -1 if error occured and errno set appropriately
669 */
670int
671fat_file_ioctl(
672    rtems_filesystem_mount_table_entry_t *mt_entry,
673    fat_file_fd_t                        *fat_fd,
674    int                                   cmd,
675    ...)
676{
677    int            rc = RC_OK;
678    fat_fs_info_t *fs_info = mt_entry->fs_info;
679    uint32_t       cur_cln = 0;
680    uint32_t       cl_start = 0;
681    uint32_t       pos = 0;
682    uint32_t      *ret;
683    va_list        ap;
684
685    va_start(ap, cmd);
686
687    switch (cmd)
688    {
689        case F_CLU_NUM:
690            pos = va_arg(ap, uint32_t);
691            ret = va_arg(ap, uint32_t *);
692
693            /* sanity check */
694            if ( pos >= fat_fd->fat_file_size ) {
695                va_end(ap);
696                rtems_set_errno_and_return_minus_one( EIO );
697            }
698
699            if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
700                (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
701            {
702                /* cluster 0 (zero) reserved for root dir */
703                *ret  = 0;
704                rc = RC_OK;
705                break;
706            }
707
708            cl_start = pos >> fs_info->vol.bpc_log2;
709
710            rc = fat_file_lseek(mt_entry, fat_fd, cl_start, &cur_cln);
711            if ( rc != RC_OK )
712                break;
713
714            *ret = cur_cln;
715            break;
716
717        default:
718            errno = EINVAL;
719            rc = -1;
720            break;
721    }
722    va_end(ap);
723    return rc;
724}
725
726/* fat_file_mark_removed --
727 *     Remove the fat-file descriptor from "valid" hash table, insert it
728 *     into "removed-but-still-open" hash table and set up "removed" bit.
729 *
730 * PARAMETERS:
731 *     fat_fd     - fat-file descriptor
732 *     mt_entry   - mount table entry
733 *
734 * RETURNS:
735 *     None
736 */
737void
738fat_file_mark_removed(
739    rtems_filesystem_mount_table_entry_t *mt_entry,
740    fat_file_fd_t                        *fat_fd
741    )
742{
743    fat_fs_info_t *fs_info = mt_entry->fs_info;
744    uint32_t       key = 0;
745
746    key = fat_construct_key(mt_entry, &fat_fd->dir_pos.sname);
747
748    _hash_delete(fs_info->vhash, key, fat_fd->ino, fat_fd);
749
750    _hash_insert(fs_info->rhash, key, fat_fd->ino, fat_fd);
751
752    fat_fd->flags |= FAT_FILE_REMOVED;
753}
754
755/* fat_file_datasync --
756 *     Synchronize fat-file -  flush all buffered data to the media.
757 *
758 * PARAMETERS:
759 *     mt_entry - mount table entry
760 *     fat_fd   - fat-file descriptor
761 *
762 * RETURNS:
763 *     RC_OK on success, or -1 if error occured and errno set appropriately
764 */
765int
766fat_file_datasync(
767    rtems_filesystem_mount_table_entry_t *mt_entry,
768    fat_file_fd_t                        *fat_fd
769    )
770{
771    int                 rc = RC_OK;
772    rtems_status_code   sc = RTEMS_SUCCESSFUL;
773    fat_fs_info_t      *fs_info = mt_entry->fs_info;
774    uint32_t            cur_cln = fat_fd->cln;
775    rtems_bdbuf_buffer *block = NULL;
776    uint32_t            sec = 0;
777    uint32_t            i = 0;
778
779    if (fat_fd->fat_file_size == 0)
780        return RC_OK;
781
782    /*
783     * we can use only one bdbuf :( and we also know that cache is useless
784     * for sync operation, so don't use it
785     */
786    rc = fat_buf_release(fs_info);
787    if (rc != RC_OK)
788        return rc;
789
790    /* for each cluster of the file ... */
791    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
792    {
793        sec = fat_cluster_num_to_sector_num(mt_entry, cur_cln);
794        /* for each sector in cluster ... */
795        for ( i = 0; i < fs_info->vol.spc; i++ )
796        {
797            /* ... sync it */
798            sc = rtems_bdbuf_read(fs_info->vol.dd, (sec + i), &block);
799            if (sc != RTEMS_SUCCESSFUL)
800                rtems_set_errno_and_return_minus_one( EIO );
801
802            sc = rtems_bdbuf_sync(block);
803            if ( sc != RTEMS_SUCCESSFUL )
804                rtems_set_errno_and_return_minus_one( EIO );
805        }
806
807        rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
808        if ( rc != RC_OK )
809            return rc;
810    }
811    return rc;
812}
813
814/* fat_file_size --
815 *     Calculate fat-file size - fat-file is nothing that clusters chain, so
816 *     go through all clusters in the chain and count it. Only
817 *     special case is root directory for FAT12/16 volumes.
818 *     This function is used only for directories which are fat-files with
819 *     non-zero length, hence 'fat_fd->cln' always contains valid data.
820 *     Calculated size is stored in 'fat_file_size' field of fat-file
821 *     descriptor.
822 *
823 * PARAMETERS:
824 *     mt_entry - mount table entry
825 *     fat_fd   - fat-file descriptor
826 *
827 * RETURNS:
828 *     RC_OK on success, or -1 if error occured (errno set appropriately)
829 */
830int
831fat_file_size(
832    rtems_filesystem_mount_table_entry_t *mt_entry,
833    fat_file_fd_t                        *fat_fd
834    )
835{
836    int            rc = RC_OK;
837    fat_fs_info_t *fs_info = mt_entry->fs_info;
838    uint32_t       cur_cln = fat_fd->cln;
839    uint32_t       save_cln = 0;
840
841    /* Have we requested root dir size for FAT12/16? */
842    if ((FAT_FD_OF_ROOT_DIR(fat_fd)) &&
843        (fs_info->vol.type & (FAT_FAT12 | FAT_FAT16)))
844    {
845        fat_fd->fat_file_size = fs_info->vol.rdir_size;
846        return rc;
847    }
848
849    fat_fd->fat_file_size = 0;
850
851    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
852    {
853        save_cln = cur_cln;
854        rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
855        if ( rc != RC_OK )
856            return rc;
857
858        fat_fd->fat_file_size += fs_info->vol.bpc;
859    }
860    fat_fd->map.last_cln = save_cln;
861    return rc;
862}
863
864/* hash support routines */
865
866/* _hash_insert --
867 *     Insert elemnt into hash based on key 'key1'
868 *
869 * PARAMETERS:
870 *     hash - hash element will be inserted into
871 *     key1 - key on which insertion is based on
872 *     key2 - not used during insertion
873 *     el   - element to insert
874 *
875 * RETURNS:
876 *     None
877 */
878static inline void
879_hash_insert(rtems_chain_control *hash, uint32_t   key1, uint32_t   key2,
880             fat_file_fd_t *el)
881{
882    rtems_chain_append((hash) + ((key1) % FAT_HASH_MODULE), &(el)->link);
883}
884
885
886/* _hash_delete --
887 *     Remove element from hash
888 *
889 * PARAMETERS:
890 *     hash - hash element will be removed from
891 *     key1 - not used
892 *     key2 - not used
893 *     el   - element to delete
894 *
895 * RETURNS:
896 *     None
897 */
898static inline void
899_hash_delete(rtems_chain_control *hash, uint32_t   key1, uint32_t   key2,
900             fat_file_fd_t *el)
901{
902    rtems_chain_extract(&(el)->link);
903}
904
905/* _hash_search --
906 *     Search element in hash. If both keys match pointer to found element
907 *     is returned
908 *
909 * PARAMETERS:
910 *     mt_entry - mount table entry
911 *     hash     - hash element will be removed from
912 *     key1     - search key
913 *     key2     - search key
914 *     ret      - placeholder for result
915 *
916 * RETURNS:
917 *     0 and pointer to found element on success, -1 otherwise
918 */
919static inline int
920_hash_search(
921    rtems_filesystem_mount_table_entry_t  *mt_entry,
922    rtems_chain_control                   *hash,
923    uint32_t                               key1,
924    uint32_t                               key2,
925    fat_file_fd_t                          **ret
926    )
927{
928    uint32_t          mod = (key1) % FAT_HASH_MODULE;
929    rtems_chain_node *the_node = rtems_chain_first(hash + mod);
930
931    for ( ; !rtems_chain_is_tail((hash) + mod, the_node) ; )
932    {
933        fat_file_fd_t *ffd = (fat_file_fd_t *)the_node;
934        uint32_t       ck =  fat_construct_key(mt_entry, &ffd->dir_pos.sname);
935
936        if ( (key1) == ck)
937        {
938            if ( ((key2) == 0) || ((key2) == ffd->ino) )
939            {
940                *ret = (void *)the_node;
941                return 0;
942            }
943        }
944        the_node = the_node->next;
945    }
946    return -1;
947}
948
949static off_t
950fat_file_lseek(
951    rtems_filesystem_mount_table_entry_t  *mt_entry,
952    fat_file_fd_t                         *fat_fd,
953    uint32_t                               file_cln,
954    uint32_t                              *disk_cln
955    )
956{
957    int rc = RC_OK;
958
959    if (file_cln == fat_fd->map.file_cln)
960        *disk_cln = fat_fd->map.disk_cln;
961    else
962    {
963        uint32_t   cur_cln;
964        uint32_t   count;
965        uint32_t   i;
966
967        if (file_cln > fat_fd->map.file_cln)
968        {
969            cur_cln = fat_fd->map.disk_cln;
970            count = file_cln - fat_fd->map.file_cln;
971        }
972        else
973        {
974            cur_cln = fat_fd->cln;
975            count = file_cln;
976        }
977
978        /* skip over the clusters */
979        for (i = 0; i < count; i++)
980        {
981            rc = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
982            if ( rc != RC_OK )
983                return rc;
984        }
985
986        /* update cache */
987        fat_fd->map.file_cln = file_cln;
988        fat_fd->map.disk_cln = cur_cln;
989
990        *disk_cln = cur_cln;
991    }
992    return RC_OK;
993}
Note: See TracBrowser for help on using the repository browser.