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

4.104.114.84.9
Last change on this file since 9fff6bf was 9fff6bf, checked in by Joel Sherrill <joel.sherrill@…>, on Mar 28, 2002 at 1:52:49 PM

2002-03-27 Ralf Corsepius <corsepiu@…>

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