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

4.104.114.84.95
Last change on this file since f91bbe64 was f91bbe64, checked in by Ralf Corsepius <ralf.corsepius@…>, on Mar 22, 2004 at 5:10:43 PM

2004-03-22 Ralf Corsepius <ralf_corsepius@…>

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