source: rtems/c/src/exec/libfs/src/dosfs/fat_file.c @ f36a7bfc

4.104.114.84.95
Last change on this file since f36a7bfc was f36a7bfc, checked in by Joel Sherrill <joel.sherrill@…>, on 02/28/02 at 20:43:50

2002-02-28 Victor V. Vengerov <vvv@…>

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