source: rtems/cpukit/libfs/src/dosfs/fat.c @ 59762963

4.104.115
Last change on this file since 59762963 was 5268642, checked in by Chris Johns <chrisj@…>, on 02/20/10 at 02:27:58

2010-02-20 Chris Johns <chrisj@…>

  • libfs/src/dosfs/fat.c, libfs/src/rfs/rtems-rfs-buffer.c: Block devices are now block device nodes and not character device nodes.
  • Property mode set to 100644
File size: 24.8 KB
Line 
1/*
2 * fat.c
3 *
4 * Low-level operations on a volume with FAT filesystem
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#if HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <fcntl.h>
19#include <unistd.h>
20#include <errno.h>
21#include <stdlib.h>
22#include <assert.h>
23
24#include <rtems/libio_.h>
25
26#include "fat.h"
27#include "fat_fat_operations.h"
28
29int
30fat_buf_access(fat_fs_info_t *fs_info, uint32_t   blk, int op_type,
31               rtems_bdbuf_buffer **buf)
32{
33    rtems_status_code sc = RTEMS_SUCCESSFUL;
34    uint8_t           i;
35    bool              sec_of_fat;
36
37
38    if (fs_info->c.state == FAT_CACHE_EMPTY)
39    {
40        if (op_type == FAT_OP_TYPE_READ)
41            sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
42        else
43            sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
44        if (sc != RTEMS_SUCCESSFUL)
45            rtems_set_errno_and_return_minus_one(EIO);
46        fs_info->c.blk_num = blk;
47        fs_info->c.modified = 0;
48        fs_info->c.state = FAT_CACHE_ACTUAL;
49    }
50
51    sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
52                  (fs_info->c.blk_num < fs_info->vol.rdir_loc));
53
54    if (fs_info->c.blk_num != blk)
55    {
56        if (fs_info->c.modified)
57        {
58            if (sec_of_fat && !fs_info->vol.mirror)
59                memcpy(fs_info->sec_buf, fs_info->c.buf->buffer,
60                       fs_info->vol.bps);
61
62            sc = rtems_bdbuf_release_modified(fs_info->c.buf);
63            fs_info->c.state = FAT_CACHE_EMPTY;
64            fs_info->c.modified = 0;
65            if (sc != RTEMS_SUCCESSFUL)
66                rtems_set_errno_and_return_minus_one(EIO);
67
68            if (sec_of_fat && !fs_info->vol.mirror)
69            {
70                rtems_bdbuf_buffer *b;
71
72                for (i = 1; i < fs_info->vol.fats; i++)
73                {
74                    sc = rtems_bdbuf_get(fs_info->vol.dev,
75                                         fs_info->c.blk_num +
76                                         fs_info->vol.fat_length * i,
77                                         &b);
78                    if ( sc != RTEMS_SUCCESSFUL)
79                        rtems_set_errno_and_return_minus_one(ENOMEM);
80                    memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
81                    sc = rtems_bdbuf_release_modified(b);
82                    if ( sc != RTEMS_SUCCESSFUL)
83                        rtems_set_errno_and_return_minus_one(ENOMEM);
84                }
85            }
86        }
87        else
88        {
89            sc = rtems_bdbuf_release(fs_info->c.buf);
90            fs_info->c.state = FAT_CACHE_EMPTY;
91            if (sc != RTEMS_SUCCESSFUL)
92                rtems_set_errno_and_return_minus_one(EIO);
93
94        }
95        if (op_type == FAT_OP_TYPE_READ)
96            sc = rtems_bdbuf_read(fs_info->vol.dev, blk, &fs_info->c.buf);
97        else
98            sc = rtems_bdbuf_get(fs_info->vol.dev, blk, &fs_info->c.buf);
99        if (sc != RTEMS_SUCCESSFUL)
100            rtems_set_errno_and_return_minus_one(EIO);
101        fs_info->c.blk_num = blk;
102        fs_info->c.state = FAT_CACHE_ACTUAL;
103    }
104    *buf = fs_info->c.buf;
105    return RC_OK;
106}
107
108int
109fat_buf_release(fat_fs_info_t *fs_info)
110{
111    rtems_status_code sc = RTEMS_SUCCESSFUL;
112    uint8_t           i;
113    bool              sec_of_fat;
114
115    if (fs_info->c.state == FAT_CACHE_EMPTY)
116        return RC_OK;
117
118    sec_of_fat = ((fs_info->c.blk_num >= fs_info->vol.fat_loc) &&
119                  (fs_info->c.blk_num < fs_info->vol.rdir_loc));
120
121    if (fs_info->c.modified)
122    {
123        if (sec_of_fat && !fs_info->vol.mirror)
124            memcpy(fs_info->sec_buf, fs_info->c.buf->buffer, fs_info->vol.bps);
125
126        sc = rtems_bdbuf_release_modified(fs_info->c.buf);
127        if (sc != RTEMS_SUCCESSFUL)
128            rtems_set_errno_and_return_minus_one(EIO);
129        fs_info->c.modified = 0;
130
131        if (sec_of_fat && !fs_info->vol.mirror)
132        {
133            rtems_bdbuf_buffer *b;
134
135            for (i = 1; i < fs_info->vol.fats; i++)
136            {
137                sc = rtems_bdbuf_get(fs_info->vol.dev,
138                                     fs_info->c.blk_num +
139                                     fs_info->vol.fat_length * i,
140                                     &b);
141                if ( sc != RTEMS_SUCCESSFUL)
142                    rtems_set_errno_and_return_minus_one(ENOMEM);
143                memcpy(b->buffer, fs_info->sec_buf, fs_info->vol.bps);
144                sc = rtems_bdbuf_release_modified(b);
145                if ( sc != RTEMS_SUCCESSFUL)
146                    rtems_set_errno_and_return_minus_one(ENOMEM);
147            }
148        }
149    }
150    else
151    {
152        sc = rtems_bdbuf_release(fs_info->c.buf);
153        if (sc != RTEMS_SUCCESSFUL)
154            rtems_set_errno_and_return_minus_one(EIO);
155    }
156    fs_info->c.state = FAT_CACHE_EMPTY;
157    return RC_OK;
158}
159
160/* _fat_block_read --
161 *     This function reads 'count' bytes from device filesystem is mounted on,
162 *     starts at 'start+offset' position where 'start' computed in sectors
163 *     and 'offset' is offset inside sector (reading may cross sectors
164 *     boundary; in this case assumed we want to read sequential sector(s))
165 *
166 * PARAMETERS:
167 *     mt_entry - mount table entry
168 *     start    - sector num to start read from
169 *     offset   - offset inside sector 'start'
170 *     count    - count of bytes to read
171 *     buff     - buffer provided by user
172 *
173 * RETURNS:
174 *     bytes read on success, or -1 if error occured
175 *     and errno set appropriately
176 */
177ssize_t
178_fat_block_read(
179    rtems_filesystem_mount_table_entry_t *mt_entry,
180    uint32_t                              start,
181    uint32_t                              offset,
182    uint32_t                              count,
183    void                                 *buff
184    )
185{
186    int                     rc = RC_OK;
187    register fat_fs_info_t *fs_info = mt_entry->fs_info;
188    ssize_t                 cmpltd = 0;
189    uint32_t                blk = start;
190    uint32_t                ofs = offset;
191    rtems_bdbuf_buffer     *block = NULL;
192    uint32_t                c = 0;
193
194    while (count > 0)
195    {
196        rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
197        if (rc != RC_OK)
198            return -1;
199
200        c = MIN(count, (fs_info->vol.bps - ofs));
201        memcpy((buff + cmpltd), (block->buffer + ofs), c);
202
203        count -= c;
204        cmpltd += c;
205        blk++;
206        ofs = 0;
207    }
208    return cmpltd;
209}
210
211/* _fat_block_write --
212 *     This function write 'count' bytes to device filesystem is mounted on,
213 *     starts at 'start+offset' position where 'start' computed in sectors
214 *     and 'offset' is offset inside sector (writing may cross sectors
215 *     boundary; in this case assumed we want to write sequential sector(s))
216 *
217 * PARAMETERS:
218 *     mt_entry - mount table entry
219 *     start    - sector num to start read from
220 *     offset   - offset inside sector 'start'
221 *     count    - count of bytes to write
222 *     buff     - buffer provided by user
223 *
224 * RETURNS:
225 *     bytes written on success, or -1 if error occured
226 *     and errno set appropriately
227 */
228ssize_t
229_fat_block_write(
230    rtems_filesystem_mount_table_entry_t *mt_entry,
231    uint32_t                              start,
232    uint32_t                              offset,
233    uint32_t                              count,
234    const void                           *buff)
235{
236    int                 rc = RC_OK;
237    fat_fs_info_t      *fs_info = mt_entry->fs_info;
238    ssize_t             cmpltd = 0;
239    uint32_t            blk  = start;
240    uint32_t            ofs = offset;
241    rtems_bdbuf_buffer *block = NULL;
242    uint32_t            c = 0;
243
244    while(count > 0)
245    {
246        c = MIN(count, (fs_info->vol.bps - ofs));
247
248        if (c == fs_info->vol.bps)
249            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_GET, &block);
250        else
251            rc = fat_buf_access(fs_info, blk, FAT_OP_TYPE_READ, &block);
252        if (rc != RC_OK)
253            return -1;
254
255        memcpy((block->buffer + ofs), (buff + cmpltd), c);
256
257        fat_buf_mark_modified(fs_info);
258
259        count -= c;
260        cmpltd +=c;
261        blk++;
262        ofs = 0;
263    }
264    return cmpltd;
265}
266
267/* _fat_block_release --
268 *     This function works around the hack that hold a bdbuf and does
269 *     not release it.
270 *
271 * PARAMETERS:
272 *     mt_entry - mount table entry
273 *
274 * RETURNS:
275 *     0 on success, or -1 if error occured and errno set appropriately
276 */
277int
278_fat_block_release(
279    rtems_filesystem_mount_table_entry_t *mt_entry)
280{
281    fat_fs_info_t *fs_info = mt_entry->fs_info;
282    return fat_buf_release(fs_info);
283}
284
285/* fat_cluster_read --
286 *     wrapper for reading a whole cluster at once
287 *
288 * PARAMETERS:
289 *     mt_entry - mount table entry
290 *     cln      - number of cluster to read
291 *     buff     - buffer provided by user
292 *
293 * RETURNS:
294 *     bytes read on success, or -1 if error occured
295 *     and errno set appropriately
296 */
297ssize_t
298fat_cluster_read(
299    rtems_filesystem_mount_table_entry_t *mt_entry,
300    uint32_t                              cln,
301    void                                 *buff
302    )
303{
304    fat_fs_info_t *fs_info = mt_entry->fs_info;
305    uint32_t       fsec = 0;
306
307    fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
308
309    return _fat_block_read(mt_entry, fsec, 0,
310                           fs_info->vol.spc << fs_info->vol.sec_log2, buff);
311}
312
313/* fat_cluster_write --
314 *     wrapper for writting a whole cluster at once
315 *
316 * PARAMETERS:
317 *     mt_entry - mount table entry
318 *     cln      - number of cluster to write
319 *     buff     - buffer provided by user
320 *
321 * RETURNS:
322 *     bytes written on success, or -1 if error occured
323 *     and errno set appropriately
324 */
325ssize_t
326fat_cluster_write(
327    rtems_filesystem_mount_table_entry_t *mt_entry,
328    uint32_t                              cln,
329    const void                           *buff
330    )
331{
332    fat_fs_info_t *fs_info = mt_entry->fs_info;
333    uint32_t       fsec = 0;
334
335    fsec = fat_cluster_num_to_sector_num(mt_entry, cln);
336
337    return _fat_block_write(mt_entry, fsec, 0,
338                          fs_info->vol.spc << fs_info->vol.sec_log2, buff);
339}
340
341/* fat_init_volume_info --
342 *     Get inforamtion about volume on which filesystem is mounted on
343 *
344 * PARAMETERS:
345 *     mt_entry - mount table entry
346 *
347 * RETURNS:
348 *     RC_OK on success, or -1 if error occured
349 *     and errno set appropriately
350 */
351int
352fat_init_volume_info(rtems_filesystem_mount_table_entry_t *mt_entry)
353{
354    rtems_status_code   sc = RTEMS_SUCCESSFUL;
355    int                 rc = RC_OK;
356    fat_fs_info_t      *fs_info = mt_entry->fs_info;
357    register fat_vol_t *vol = &fs_info->vol;
358    uint32_t            data_secs = 0;
359    char                boot_rec[FAT_MAX_BPB_SIZE];
360    char                fs_info_sector[FAT_USEFUL_INFO_SIZE];
361    ssize_t             ret = 0;
362    struct stat         stat_buf;
363    int                 i = 0;
364    rtems_bdbuf_buffer *block = NULL;
365
366    rc = stat(mt_entry->dev, &stat_buf);
367    if (rc == -1)
368        return rc;
369
370    /* Must be a block device. */
371    if (!S_ISBLK(stat_buf.st_mode))
372        rtems_set_errno_and_return_minus_one(ENOTTY);
373
374    /* check that device is registred as block device and lock it */
375    vol->dd = rtems_disk_obtain(stat_buf.st_rdev);
376    if (vol->dd == NULL)
377        rtems_set_errno_and_return_minus_one(EIO);
378
379    vol->dev = stat_buf.st_rdev;
380
381    /* Read boot record */
382    /* FIXME: Asserts FAT_MAX_BPB_SIZE < bdbuf block size */
383    sc = rtems_bdbuf_read( vol->dev, 0, &block);
384    if (sc != RTEMS_SUCCESSFUL)
385    {
386        rtems_disk_release(vol->dd);
387        rtems_set_errno_and_return_minus_one( EIO);
388    }
389
390    memcpy( boot_rec, block->buffer, FAT_MAX_BPB_SIZE);
391
392    sc = rtems_bdbuf_release( block);
393    if (sc != RTEMS_SUCCESSFUL)
394    {
395        rtems_disk_release(vol->dd);
396        rtems_set_errno_and_return_minus_one( EIO );
397    }
398
399    /* Evaluate boot record */
400    vol->bps = FAT_GET_BR_BYTES_PER_SECTOR(boot_rec);
401
402    if ( (vol->bps != 512)  &&
403         (vol->bps != 1024) &&
404         (vol->bps != 2048) &&
405         (vol->bps != 4096))
406    {
407        rtems_disk_release(vol->dd);
408        rtems_set_errno_and_return_minus_one( EINVAL );
409    }
410
411    for (vol->sec_mul = 0, i = (vol->bps >> FAT_SECTOR512_BITS); (i & 1) == 0;
412         i >>= 1, vol->sec_mul++);
413    for (vol->sec_log2 = 0, i = vol->bps; (i & 1) == 0;
414         i >>= 1, vol->sec_log2++);
415
416    vol->spc = FAT_GET_BR_SECTORS_PER_CLUSTER(boot_rec);
417    /*
418     * "sectors per cluster" of zero is invalid
419     * (and would hang the following loop)
420     */
421    if (vol->spc == 0)
422    {
423        rtems_disk_release(vol->dd);
424        rtems_set_errno_and_return_minus_one(EINVAL);
425    }
426
427    for (vol->spc_log2 = 0, i = vol->spc; (i & 1) == 0;
428         i >>= 1, vol->spc_log2++);
429
430    /*
431     * "bytes per cluster" value greater than 32K is invalid
432     */
433    if ((vol->bpc = vol->bps << vol->spc_log2) > MS_BYTES_PER_CLUSTER_LIMIT)
434    {
435        rtems_disk_release(vol->dd);
436        rtems_set_errno_and_return_minus_one(EINVAL);
437    }
438
439    for (vol->bpc_log2 = 0, i = vol->bpc; (i & 1) == 0;
440         i >>= 1, vol->bpc_log2++);
441
442    vol->fats = FAT_GET_BR_FAT_NUM(boot_rec);
443    vol->fat_loc = FAT_GET_BR_RESERVED_SECTORS_NUM(boot_rec);
444
445    vol->rdir_entrs = FAT_GET_BR_FILES_PER_ROOT_DIR(boot_rec);
446
447    /* calculate the count of sectors occupied by the root directory */
448    vol->rdir_secs = ((vol->rdir_entrs * FAT_DIRENTRY_SIZE) + (vol->bps - 1)) /
449                     vol->bps;
450
451    vol->rdir_size = vol->rdir_secs << vol->sec_log2;
452
453    if ( (FAT_GET_BR_SECTORS_PER_FAT(boot_rec)) != 0)
454        vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT(boot_rec);
455    else
456        vol->fat_length = FAT_GET_BR_SECTORS_PER_FAT32(boot_rec);
457
458    vol->data_fsec = vol->fat_loc + vol->fats * vol->fat_length +
459                     vol->rdir_secs;
460
461    /* for  FAT12/16 root dir starts at(sector) */
462    vol->rdir_loc = vol->fat_loc + vol->fats * vol->fat_length;
463
464    if ( (FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec)) != 0)
465        vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM16(boot_rec);
466    else
467        vol->tot_secs = FAT_GET_BR_TOTAL_SECTORS_NUM32(boot_rec);
468
469    data_secs = vol->tot_secs - vol->data_fsec;
470
471    vol->data_cls = data_secs / vol->spc;
472
473    /* determine FAT type at least */
474    if ( vol->data_cls < FAT_FAT12_MAX_CLN)
475    {
476        vol->type = FAT_FAT12;
477        vol->mask = FAT_FAT12_MASK;
478        vol->eoc_val = FAT_FAT12_EOC;
479    }
480    else
481    {
482        if ( vol->data_cls < FAT_FAT16_MAX_CLN)
483        {
484            vol->type = FAT_FAT16;
485            vol->mask = FAT_FAT16_MASK;
486            vol->eoc_val = FAT_FAT16_EOC;
487        }
488        else
489        {
490            vol->type = FAT_FAT32;
491            vol->mask = FAT_FAT32_MASK;
492            vol->eoc_val = FAT_FAT32_EOC;
493        }
494    }
495
496    if (vol->type == FAT_FAT32)
497    {
498        vol->rdir_cl = FAT_GET_BR_FAT32_ROOT_CLUSTER(boot_rec);
499
500        vol->mirror = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_MIRROR;
501        if (vol->mirror)
502            vol->afat = FAT_GET_BR_EXT_FLAGS(boot_rec) & FAT_BR_EXT_FLAGS_FAT_NUM;
503        else
504            vol->afat = 0;
505
506        vol->info_sec = FAT_GET_BR_FAT32_FS_INFO_SECTOR(boot_rec);
507        if( vol->info_sec == 0 )
508        {
509            rtems_disk_release(vol->dd);
510            rtems_set_errno_and_return_minus_one( EINVAL );
511        }
512        else
513        {
514            ret = _fat_block_read(mt_entry, vol->info_sec , 0,
515                                  FAT_FSI_LEADSIG_SIZE, fs_info_sector);
516            if ( ret < 0 )
517            {
518                rtems_disk_release(vol->dd);
519                return -1;
520            }
521
522            if (FAT_GET_FSINFO_LEAD_SIGNATURE(fs_info_sector) !=
523                FAT_FSINFO_LEAD_SIGNATURE_VALUE)
524            {
525                _fat_block_release(mt_entry);
526                rtems_disk_release(vol->dd);
527                rtems_set_errno_and_return_minus_one( EINVAL );
528            }
529            else
530            {
531                ret = _fat_block_read(mt_entry, vol->info_sec , FAT_FSI_INFO,
532                                      FAT_USEFUL_INFO_SIZE, fs_info_sector);
533                if ( ret < 0 )
534                {
535                    _fat_block_release(mt_entry);
536                    rtems_disk_release(vol->dd);
537                    return -1;
538                }
539
540                vol->free_cls = FAT_GET_FSINFO_FREE_CLUSTER_COUNT(fs_info_sector);
541                vol->next_cl = FAT_GET_FSINFO_NEXT_FREE_CLUSTER(fs_info_sector);
542                rc = fat_fat32_update_fsinfo_sector(mt_entry, 0xFFFFFFFF,
543                                                    0xFFFFFFFF);
544                if ( rc != RC_OK )
545                {
546                    _fat_block_release(mt_entry);
547                    rtems_disk_release(vol->dd);
548                    return rc;
549                }
550            }
551        }
552    }
553    else
554    {
555        vol->rdir_cl = 0;
556        vol->mirror = 0;
557        vol->afat = 0;
558        vol->free_cls = 0xFFFFFFFF;
559        vol->next_cl = 0xFFFFFFFF;
560    }
561
562    _fat_block_release(mt_entry);
563
564    vol->afat_loc = vol->fat_loc + vol->fat_length * vol->afat;
565
566    /* set up collection of fat-files fd */
567    fs_info->vhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
568    if ( fs_info->vhash == NULL )
569    {
570        rtems_disk_release(vol->dd);
571        rtems_set_errno_and_return_minus_one( ENOMEM );
572    }
573
574    for (i = 0; i < FAT_HASH_SIZE; i++)
575        rtems_chain_initialize_empty(fs_info->vhash + i);
576
577    fs_info->rhash = calloc(FAT_HASH_SIZE, sizeof(rtems_chain_control));
578    if ( fs_info->rhash == NULL )
579    {
580        rtems_disk_release(vol->dd);
581        free(fs_info->vhash);
582        rtems_set_errno_and_return_minus_one( ENOMEM );
583    }
584    for (i = 0; i < FAT_HASH_SIZE; i++)
585        rtems_chain_initialize_empty(fs_info->rhash + i);
586
587    fs_info->uino_pool_size = FAT_UINO_POOL_INIT_SIZE;
588    fs_info->uino_base = (vol->tot_secs << vol->sec_mul) << 4;
589    fs_info->index = 0;
590    fs_info->uino = (char *)calloc(fs_info->uino_pool_size, sizeof(char));
591    if ( fs_info->uino == NULL )
592    {
593        rtems_disk_release(vol->dd);
594        free(fs_info->vhash);
595        free(fs_info->rhash);
596        rtems_set_errno_and_return_minus_one( ENOMEM );
597    }
598    fs_info->sec_buf = (uint8_t *)calloc(vol->bps, sizeof(uint8_t));
599    if (fs_info->sec_buf == NULL)
600    {
601        rtems_disk_release(vol->dd);
602        free(fs_info->vhash);
603        free(fs_info->rhash);
604        free(fs_info->uino);
605        rtems_set_errno_and_return_minus_one( ENOMEM );
606    }
607
608    return RC_OK;
609}
610
611/* fat_shutdown_drive --
612 *     Free all allocated resources and synchronize all necessary data
613 *
614 * PARAMETERS:
615 *     mt_entry - mount table entry
616 *
617 * RETURNS:
618 *     RC_OK on success, or -1 if error occured
619 *     and errno set appropriately
620 */
621int
622fat_shutdown_drive(rtems_filesystem_mount_table_entry_t *mt_entry)
623{
624    int            rc = RC_OK;
625    fat_fs_info_t *fs_info = mt_entry->fs_info;
626    int            i = 0;
627
628    if (fs_info->vol.type & FAT_FAT32)
629    {
630        rc = fat_fat32_update_fsinfo_sector(mt_entry, fs_info->vol.free_cls,
631                                            fs_info->vol.next_cl);
632        if ( rc != RC_OK )
633            rc = -1;
634    }
635
636    fat_buf_release(fs_info);
637
638    if (rtems_bdbuf_syncdev(fs_info->vol.dev) != RTEMS_SUCCESSFUL)
639        rc = -1;
640
641    for (i = 0; i < FAT_HASH_SIZE; i++)
642    {
643        rtems_chain_node    *node = NULL;
644        rtems_chain_control *the_chain = fs_info->vhash + i;
645
646        while ( (node = rtems_chain_get(the_chain)) != NULL )
647            free(node);
648    }
649
650    for (i = 0; i < FAT_HASH_SIZE; i++)
651    {
652        rtems_chain_node    *node = NULL;
653        rtems_chain_control *the_chain = fs_info->rhash + i;
654
655        while ( (node = rtems_chain_get(the_chain)) != NULL )
656            free(node);
657    }
658
659    free(fs_info->vhash);
660    free(fs_info->rhash);
661
662    free(fs_info->uino);
663    free(fs_info->sec_buf);
664    rtems_disk_release(fs_info->vol.dd);
665
666    if (rc)
667        errno = EIO;
668    return rc;
669}
670
671/* fat_init_clusters_chain --
672 *     Zeroing contents of all clusters in the chain
673 *
674 * PARAMETERS:
675 *     mt_entry          - mount table entry
676 *     start_cluster_num - num of first cluster in the chain
677 *
678 * RETURNS:
679 *     RC_OK on success, or -1 if error occured
680 *     and errno set appropriately
681 */
682int
683fat_init_clusters_chain(
684    rtems_filesystem_mount_table_entry_t *mt_entry,
685    uint32_t                              start_cln
686    )
687{
688    int                     rc = RC_OK;
689    ssize_t                 ret = 0;
690    register fat_fs_info_t *fs_info = mt_entry->fs_info;
691    uint32_t                cur_cln = start_cln;
692    char                   *buf;
693
694    buf = calloc(fs_info->vol.bpc, sizeof(char));
695    if ( buf == NULL )
696        rtems_set_errno_and_return_minus_one( EIO );
697
698    while ((cur_cln & fs_info->vol.mask) < fs_info->vol.eoc_val)
699    {
700        ret = fat_cluster_write(mt_entry, cur_cln, buf);
701        if ( ret == -1 )
702        {
703            free(buf);
704            return -1;
705        }
706
707        rc  = fat_get_fat_cluster(mt_entry, cur_cln, &cur_cln);
708        if ( rc != RC_OK )
709        {
710            free(buf);
711            return rc;
712        }
713
714    }
715    free(buf);
716    return rc;
717}
718
719#define FAT_UNIQ_INO_BASE 0x0FFFFF00
720
721#define FAT_UNIQ_INO_IS_BUSY(index, arr) \
722  (((arr)[((index)>>3)]>>((index) & (8-1))) & 0x01)
723
724#define FAT_SET_UNIQ_INO_BUSY(index, arr) \
725  ((arr)[((index)>>3)] |= (0x01<<((index) & (8-1))))
726
727#define FAT_SET_UNIQ_INO_FREE(index, arr) \
728  ((arr)[((index)>>3)] &= (~(0x01<<((index) & (8-1)))))
729
730/* fat_get_unique_ino --
731 *     Allocate unique ino from unique ino pool
732 *
733 * PARAMETERS:
734 *     mt_entry - mount table entry
735 *
736 * RETURNS:
737 *     unique inode number on success, or 0 if there is no free unique inode
738 *     number in the pool
739 *
740 * ATTENTION:
741 *     0 means FAILED !!!
742 *
743 */
744uint32_t
745fat_get_unique_ino(rtems_filesystem_mount_table_entry_t *mt_entry)
746{
747    register fat_fs_info_t *fs_info = mt_entry->fs_info;
748    uint32_t                j = 0;
749    bool                    resrc_unsuff = false;
750
751    while (!resrc_unsuff)
752    {
753        for (j = 0; j < fs_info->uino_pool_size; j++)
754        {
755            if (!FAT_UNIQ_INO_IS_BUSY(fs_info->index, fs_info->uino))
756            {
757                FAT_SET_UNIQ_INO_BUSY(fs_info->index, fs_info->uino);
758                return (fs_info->uino_base + fs_info->index);
759            }
760            fs_info->index++;
761            if (fs_info->index >= fs_info->uino_pool_size)
762                fs_info->index = 0;
763        }
764
765        if ((fs_info->uino_pool_size << 1) < (0x0FFFFFFF - fs_info->uino_base))
766        {
767            fs_info->uino_pool_size <<= 1;
768            fs_info->uino = realloc(fs_info->uino, fs_info->uino_pool_size);
769            if (fs_info->uino != NULL)
770                fs_info->index = fs_info->uino_pool_size;
771            else
772                resrc_unsuff = true;
773        }
774        else
775            resrc_unsuff = true;
776    }
777    return 0;
778}
779
780/* fat_free_unique_ino --
781 *     Return unique ino to unique ino pool
782 *
783 * PARAMETERS:
784 *     mt_entry - mount table entry
785 *     ino      - inode number to free
786 *
787 * RETURNS:
788 *     None
789 */
790void
791fat_free_unique_ino(
792    rtems_filesystem_mount_table_entry_t *mt_entry,
793    uint32_t                              ino
794    )
795{
796    fat_fs_info_t *fs_info = mt_entry->fs_info;
797
798    FAT_SET_UNIQ_INO_FREE((ino - fs_info->uino_base), fs_info->uino);
799}
800
801/* fat_ino_is_unique --
802 *     Test whether ino is from unique ino pool
803 *
804 * PARAMETERS:
805 *     mt_entry - mount table entry
806 *     ino   - ino to be tested
807 *
808 * RETURNS:
809 *     true if ino is allocated from unique ino pool, false otherwise
810 */
811inline bool
812fat_ino_is_unique(
813    rtems_filesystem_mount_table_entry_t *mt_entry,
814    uint32_t                              ino
815    )
816{
817    fat_fs_info_t *fs_info = mt_entry->fs_info;
818
819    return (ino >= fs_info->uino_base);
820}
821
822/* fat_fat32_update_fsinfo_sector --
823 *     Synchronize fsinfo sector for FAT32 volumes
824 *
825 * PARAMETERS:
826 *     mt_entry   - mount table entry
827 *     free_count - count of free clusters
828 *     next_free  - the next free cluster num
829 *
830 * RETURNS:
831 *     RC_OK on success, or -1 if error occured (errno set appropriately)
832 */
833int
834fat_fat32_update_fsinfo_sector(
835    rtems_filesystem_mount_table_entry_t *mt_entry,
836    uint32_t                              free_count,
837    uint32_t                              next_free
838    )
839{
840    ssize_t                 ret1 = 0, ret2 = 0;
841    register fat_fs_info_t *fs_info = mt_entry->fs_info;
842    uint32_t                le_free_count = 0;
843    uint32_t                le_next_free = 0;
844
845    le_free_count = CT_LE_L(free_count);
846    le_next_free = CT_LE_L(next_free);
847
848    ret1 = _fat_block_write(mt_entry,
849                            fs_info->vol.info_sec,
850                            FAT_FSINFO_FREE_CLUSTER_COUNT_OFFSET,
851                            4,
852                            (char *)(&le_free_count));
853
854    ret2 = _fat_block_write(mt_entry,
855                            fs_info->vol.info_sec,
856                            FAT_FSINFO_NEXT_FREE_CLUSTER_OFFSET,
857                            4,
858                            (char *)(&le_next_free));
859
860    if ( (ret1 < 0) || (ret2 < 0) )
861        return -1;
862
863    return RC_OK;
864}
Note: See TracBrowser for help on using the repository browser.